WPF:如何在调整大小后保持ListBox SelectedItem可见?

时间:2018-11-21 13:51:54

标签: c# wpf xaml scroll listbox

在我们当前的C# MVVM项目中,我们使用ListBox显示项目。

还有一个可以在列表框下方展开的容器。

一切正常。容器展开后,ListBox收缩,ScrollBar出现。

但是,如果在列表框的底部选择了一个元素,并且容器已展开,则该项目会在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或其他任何内容上我都找不到任何东西。

我已经看到可以以编程方式滚动:

我还看到有可能知道何时出现ListBoxItemherethere),但是由于我的物品已经加载,所以隐藏了,我不认为这会起作用。

我不想隐藏代码,我必须在需要此功能的每个视图中进行复制。我曾考虑过在ListBox所附的行为中实施此操作,但我高度怀疑这是否是最佳解决方案。

我还考虑过编写自定义ListBox控件,但是对于这么小的功能,我认为这太多了。

有人可以告诉我实现这种行为的最佳方法吗? 预先感谢。

1 个答案:

答案 0 :(得分:1)

Behavior是将此功能添加到控件的理想方法。选择更改或调整大小后,下面的代码将滚动列表框的SelectedItem进入视图。

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>

关于我最近的blog post的行为的更多讨论。