Запретить ScrollViewer в TabItem сбросить смещение при изменении вкладки

У меня есть такой код:

<TabItem Header="Card Details">
    <ScrollViewer Name="cardDetailsScroll" MaxHeight="600" Width="Auto" Padding="10">
        <StackPanel>
            <Canvas Height="50">
            </Canvas>
            ...
        </StackPanel>
    </ScrollViewer>
</TabItem>

Каждый раз, когда я меняю вкладку, затем возвращаюсь, ScrollViewer сбрасывает свое смещение (вверх). Я ошибаюсь при использовании StackPanel? Или я что-то упустил?

Спасибо.


person Onfealive    schedule 14.11.2016    source источник


Ответы (3)


Это ожидаемое поведение WPF, как вы можете прочитать в ветке ЭТОГО. Если вы используете MVVM, вы можете связать позицию смещения средства просмотра прокрутки, используя прикрепленное поведение, предложенное ЗДЕСЬ, или, если вы предпочитаете настраивать элемент управления вкладкой, первая ссылка содержит хорошую отправную точку.

person Daniel Leiszen    schedule 14.11.2016

Из первой ссылки Даниэля Лейсена:

По умолчанию WPF выгружает невидимые элементы, включая выгрузку невидимых элементов вкладок. Это означает, что когда вы вернетесь на вкладку, TabItem будет повторно загружен, и все, что не связано (например, позиция прокрутки), будет сброшено.

Я думал об этом решении еще до того, как спросил, я просто хочу знать еще несколько решений, которые помогут мне улучшить свои знания:

private void cardDetailsScroll_Loaded(object sender, RoutedEventArgs e)
{
    double offset;
    if (cardDetailsScroll.Tag != null 
         && double.TryParse(cardDetailsScroll.Tag.ToString(), out offset))
    {
        cardDetailsScroll.ScrollToVerticalOffset(offset);                
    }
}

private void cardDetailsScroll_Unloaded(object sender, RoutedEventArgs e)
{
    cardDetailsScroll.Tag = cardDetailsScroll.VerticalOffset;
}
person Onfealive    schedule 15.11.2016
comment
Думаю, я дал вам два разных решения: привязка (которую я лично предпочитаю) подходит, когда вы используете MVVM (и я бы посоветовал вам это сделать), и настраиваемый элемент управления. Это как действительные, так и многоразовые решения. Вы, безусловно, можете сохранить позицию прокрутки в другом месте, например. свойство Tag. Я бы не стал этого предлагать, поскольку это не универсальное решение, и его сложнее повторно использовать, когда вам нужно где-то еще. В любом случае, из вашего вопроса было неясно, что у вас уже есть на него ответ. Мое плохое, извините за ответ. - person Daniel Leiszen; 15.11.2016
comment
@DanielLeiszen Я узнаю больше, чтобы понять 2 этого решения. Может быть, я смогу использовать их в будущем. Спасибо. - person Onfealive; 19.11.2016
comment
Этот работает (на загруженных и выгруженных). Было сложно даже погуглить проблему. Искал и искал, что в коде все время выставляло позицию на 0 при переключении вкладок. - person Wolf5; 30.11.2017

У меня была аналогичная проблема с TabControl. Каждая вкладка показывает графику из UserControl, и когда я переключался между вкладками, средство просмотра прокрутки прокручивалось обратно в исходную точку после активации вкладки.

Я использовал подход, аналогичный предложенному Onfealive. Но я использовал HorizontalOffset и VerticalOffset вместо Tag.

    private void m_ScrollViewer_Loaded(object sender, RoutedEventArgs e)
    {
        m_ScrollViewer.ScrollToHorizontalOffset(m_HorizontalOffset);
        m_ScrollViewer.ScrollToVerticalOffset(m_VerticalOffset);
    }

    private void m_ScrollViewer_Unloaded(object sender, RoutedEventArgs e)
    {
        m_HorizontalOffset = m_ScrollViewer.HorizontalOffset;
        m_VerticalOffset = m_ScrollViewer.VerticalOffset;
    }

Это работает для меня, и я думаю, что этот подход более безопасен!

person Mehrdad Ordoobadi    schedule 04.02.2018
comment
В моем случае мне нужно вызвать действия внутри обработчика Loaded в Application.Current.Dispatcher.InvokeAsync с помощью DispatcherPriority.Send. - person YantingChen; 02.02.2021