在 WPF ListView 中启用多选






3.50/5 (6投票s)
使您的 ListView 支持通过拖动选择项目。
引言
本文演示了如何创建一个组件,使您的 ListView 支持多选。
背景
我当时在开发一个文件列表,我并没有太在意选择模式,因为我以为将ListView.SelectionMode
设置为Multiple
/Extended
可以通过点击和拖动在ListView
中选择多个项目。(我的.NET 1.1 书就是这么告诉我的。)
然后,当快要完成时,我花时间做了更多的测试,却无法选择多个项目。这非常令人恼火,所以我将SelectionMode
设置为Multiple
。
<ListView SelectionMode="Multiple" .../>
我重新编译了,但似乎没有起作用。 我将SelectionMode
更改为Extended
,但仍然不起作用。
我发现虽然它允许我使用 Control 和 Shift 选择多个项目,但我无法使用鼠标拖动来选择。我不确定其他人怎么想,但这对我来说确实是一个很大的惊喜。
奇怪的是,即使这是一个大问题,我也无法通过Google找到一个有用的/完整的解决方案来允许多重选择,所以我用我有限的 WPF 知识开发了这个组件。
我的设计过程
刚开始的时候,我试图找到每个ListViewItem
的位置,并将其与所选区域进行比较; 我做了一些研究,但没有成功
- 似乎没有一个通用的地方来存储哪个
ListViewItem
位于哪里,除非您开发了自己的Panel
。 - 似乎可以重写
TreeViewItem
的OnMouseMove
,但这会将您的ListView
限制为仅在StackPanel
模板中使用,因为它需要您的鼠标位于TreeViewItem
之上。(请参阅演示项目中的MultiSelectListView
。) Arrange
方法仅公开大小,ArrangeCore
方法可以公开一个矩形,但是它是sealed
。
经过一番谷歌搜索后,我发现了一个名为VisualTreeHelper.HitTest
的方法,它接受
- 一个控件,
- 一个过滤器函数,(通过此函数检索选定的项目)
- 一个结果回调,以及
- 一个矩形。
并返回指定矩形中的子项。
它做了我想要的,但是HitTest
方法只能返回可见的项目,所以如果我开始选择,然后向下滚动,它只会搜索屏幕上的项目,而不是隐藏的项目。 然后通过两次HitTest
修复了此问题,首先取消选择所有可见项目,然后选择选定的可见项目。
//Unselect all visible selected items no matter if it's current selected or not.
VisualTreeHelper.HitTest(lvSender, UnselectHitTestFilterFunc,
new HitTestResultCallback(SelectResultCallback),
new GeometryHitTestParameters(new RectangleGeometry(unselectRect)));
//Select all visible items in select region.
VisualTreeHelper.HitTest(lvSender, SelectHitTestFilterFunc,
new HitTestResultCallback(SelectResultCallback),
new GeometryHitTestParameters(new RectangleGeometry(selectRect)));
最后一个问题是绘制预览矩形,该矩形在选择时可见。 由于我的知识有限,我所能做的就是在背景中绘制它。 如果您有更好的解决方案,请发布。(如您所见,预览矩形无法处理滚动;我尚未弄清楚如何获取滚动信息。)
lvSender.Background = new DrawingBrush(
DrawRectangle(selectRect, lvSender.ActualWidth, lvSender.ActualHeight));
使用代码
我为此操作创建了一个组件,您可以将代码包含在您的项目中,并设置一个Attached
属性来启用多选。 您可能必须设置ItemPanel
模板,以便有空间开始拖动。
<ListView cont:ListViewSelectionHelper.MultiSelect="True"
cont:ListViewSelectionHelper.PreviewDrag="True">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Margin="0,0,20,0" IsItemsHost="True" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.Items>
<TextBlock>Test1</TextBlock>
<TextBlock>Test2</TextBlock>
<TextBlock>Test3</TextBlock>
<TextBlock>Test4</TextBlock>
<TextBlock>Test5</TextBlock>
</ListView.Items>
</ListView>
设置MultiSelect
会将四个事件附加到您的ListView
PreviewMouseDown
,用于清除选择。MouseDown
,用于启用IsDragging
附加属性。MouseUp
,用于禁用IsDragging
附加属性。MouseMove
,如果IsDragging
,则选择项目。
在我的文件列表中启用 MultiSelect 时的外观
历史
- 05-02-08:初始版本(希望不是最后一个版本)。
- 05-13-08:版本 2,修复了三个错误
- 如果滚动条不可见,则无法拖动。
- 拖动后出现奇怪的选择效果。
- Shift+Select 未按预期工作。