【问题标题】:WPF: How to keep ListBox SelectedItem visible after resizing?WPF:如何在调整大小后保持 ListBox SelectedItem 可见?
【发布时间】:2019-04-24 02:41:57
【问题描述】:

在我们当前的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 何时进入视野(herethere),但由于我的项目已经加载然后隐藏,我认为这不会起作用。

我不想在需要此功能的每个视图中都复制代码隐藏。我曾考虑在附加到ListBox 的行为中实现这一点,但我非常怀疑这是否是最好的解决方案。

我也考虑过编写一个自定义的ListBox 控件,但我认为这对于这么小的功能来说太过分了。

有人能告诉我实现这种行为的最佳方法吗? 提前致谢。

【问题讨论】:

    标签: c# wpf xaml scroll listbox


    【解决方案1】:

    Behavior 是将此功能添加到控件的理想方式。下面的代码将在选择更改或调整大小后将 ListBox 的 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行为的讨论。

    【讨论】:

    • 非常感谢!这正是我所需要的!我只是不明白为什么你也听 selectionChanged 并且不得不删除这部分,因为我们允许多项选择。但再一次,谢谢你。我会好好看看你的博客!
    • SelectionChanged 是这个行为最初设计用来处理的——当你从代码后面或通过绑定选择一个项目时,它会滚动到视图中。
    • 哦,我明白了,谢谢!我不需要这部分,因为它不会在我的情况下发生,但有一天它可能会有用。再次感谢您
    • 也许最好做两种不同的行为——每个事件一个。然后,您可以添加适合每个特定 Listbox 实例的任何内容。
    猜你喜欢
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 2018-10-17
    • 1970-01-01
    • 2015-02-11
    • 1970-01-01
    • 2018-05-02
    相关资源
    最近更新 更多