WPF:如何在调整大小后保持 ListBox SelectedItem 可见?
WPF: How to keep ListBox SelectedItem visible after resizing?
在我们当前的 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
何时进入视图 ( and there),但由于我的项目已经加载然后隐藏,我认为这行不通。
我不想在需要此功能的每个视图中都必须复制代码隐藏。我考虑过在附加到 ListBox
的行为中实现它,但我非常怀疑这将是最好的解决方案。
我也考虑过编写自定义 ListBox
控件,但我认为这对于这么小的功能来说太多了。
有人能告诉我实现这种行为的最佳方法吗?
提前致谢。
A 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 的行为的更多讨论。
在我们当前的 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
控件,但我认为这对于这么小的功能来说太多了。
有人能告诉我实现这种行为的最佳方法吗? 提前致谢。
A 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 的行为的更多讨论。