WPF: Как сохранить ListBox SelectedItem видимым после изменения размера? - PullRequest
0 голосов
/ 21 ноября 2018

В нашем текущем проекте C# MVVM мы используем ListBox для отображения элементов.

Существует еще один контейнер, который можно расширить ниже ListBox.

Все работаетхорошо.Когда контейнер расширяется, ListBox сжимается и появляется ScrollBar.

Однако, если элемент выбран в нижней части ListBox и контейнер расширяется, элемент исчезает в конце ListBox.

Пример:

До расширения контейнера:

+--------------+
| Item 1       |
+--------------+
| Item 2       |
+--------------+
| Item 3       |
+--------------+
| Item 4       |
+--------------+
| SelectedItem |
+--------------+
| Item 6       |
+--------------+
| Item 7       |
+--------------+

+------------------+
| Container        |
+------------------+

После расширения контейнера:

+--------------+---+
| Item 1       | S |
+--------------+ c |
| Item 2       | r |
+--------------+ o |
| Item 3       | l |
+--------------+ l |
| Item 4       |   |
+--------------+---+

+------------------+
|                  |
|                  |
| Container        |
|                  |
|                  |
+------------------+

Чего я хотел бы добиться, так это сохранитьвидимый SelectedItem без необходимости прокрутки к нему.

Примерно так:

+--------------+---+
| Item 2       | S |
+--------------+ c |
| Item 3       | r |
+--------------+ o |
| Item 4       | l |
+--------------+ l |
| SelectedItem |   |
+--------------+---+

+------------------+
|                  |
|                  |
| Container        |
|                  |
|                  |
+------------------+

Каков наилучший способ добиться этого?

Я не смог ничего найтиоб этом здесь, на SO или чем-то еще.

Я видел, что можно прокручивать программно:

Я также видел, что можно было узнать, когда появляется ListBoxItem ( здесь и там ) но поскольку мои элементы уже загружены и скрыты, я не думаю, что это сработает.

Я не хочу иметь код позадиЯ должен копировать в каждом представлении, где мне нужна эта функциональность.Я думал о реализации этого в поведении, присоединенном к ListBox, но я очень сомневаюсь, что это будет лучшим решением.

Я также думал о написании пользовательского ListBox элемента управления, но я думаю, что это слишкоммного для такой маленькой функциональности.

Может кто-нибудь сказать мне лучший способ добиться такого поведения?Заранее спасибо.

1 Ответ

0 голосов
/ 21 ноября 2018

A Behavior - это идеальный способ добавить эту функцию в элемент управления.Приведенный ниже код прокручивает выбранный элемент ListBox после его изменения или изменения размера.

public class perListBoxHelper : Behavior<ListBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
        AssociatedObject.SizeChanged += AssociatedObject_SizeChanged;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.SelectionChanged -= AssociatedObject_SelectionChanged;
        AssociatedObject.SizeChanged -= AssociatedObject_SizeChanged;
        base.OnDetaching();
    }

    private static void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        ScrollSelectionIntoView(sender as ListBox);
    }

    private static void AssociatedObject_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        ScrollSelectionIntoView(sender as ListBox);
    }

    private static void ScrollSelectionIntoView(ListBox listBox)
    { 
        if (listBox?.SelectedItem == null)
            return;

        Action action = () =>
        {
            listBox.UpdateLayout();
            listBox.ScrollIntoView(listBox.SelectedItem);
        };

        listBox.Dispatcher.BeginInvoke(action, DispatcherPriority.ContextIdle);
    }
}

Использование

<ListBox ... >
    <i:Interaction.Behaviors>
        <vhelp:perListBoxHelper />
    </i:Interaction.Behaviors>
</ListBox>

Дополнительные обсуждения поведения в моем недавнем сообщении в блоге .

...