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 拖放 - 使选择保持活动状态