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

Posted

技术标签:

【中文标题】WPF:如何在调整大小后保持 ListBox SelectedItem 可见?【英文标题】:WPF: How to keep ListBox SelectedItem visible after resizing? 【发布时间】: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 或其他任何地方都找不到任何关于它的信息。

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

https://social.msdn.microsoft.com/Forums/vstudio/en-US/a9116965-b1e9-411c-b153-b868e0a730cf/how-to-programmatically-scroll-a-scrollviewer?forum=wpf

https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.scrollviewer.scrolltohorizontaloffset?redirectedfrom=MSDN&view=netframework-4.7.2#System_Windows_Controls_ScrollViewer_ScrollToHorizontalOffset_System_Double_

https://wpf.2000things.com/2013/08/21/889-scrolling-a-scrollviewer-from-code/

我还看到可以知道ListBoxItem 何时进入视野(here 和 there),但由于我的项目已经加载然后隐藏,我认为这不会起作用。

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

我也考虑过编写一个自定义的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 实例的任何内容。

以上是关于WPF:如何在调整大小后保持 ListBox SelectedItem 可见?的主要内容,如果未能解决你的问题,请参考以下文章

使用 gon-wpf 的 ListBox 拖放 - 使选择保持活动状态

WPF:如何在弹出窗口中自动调整 WebBrowser 的大小?

调整大小后通过鼠标连续调整其余图像的大小,并保持比例

如何在旋转和调整大小后设置矩形的中心点,保持旧位置

阻止 ListBox 使用内容而不是窗口来调整大小

调整窗口大小时调整 Tkinter Listbox 小部件的大小