65.9K
CodeProject 正在变化。 阅读更多。
Home

在 WPF ListView 中启用多选

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.50/5 (6投票s)

2008 年 5 月 2 日

LGPL3

3分钟阅读

viewsIcon

101038

downloadIcon

1566

使您的 ListView 支持通过拖动选择项目。

引言

本文演示了如何创建一个组件,使您的 ListView 支持多选。

背景

我当时在开发一个文件列表,我并没有太在意选择模式,因为我以为ListView.SelectionMode设置为Multiple/Extended可以通过点击和拖动在ListView中选择多个项目。(我的.NET 1.1 书就是这么告诉我的。)

然后,当快要完成时,我花时间做了更多的测试,却无法选择多个项目。这非常令人恼火,所以我将SelectionMode设置为Multiple

<ListView SelectionMode="Multiple"  .../>

我重新编译了,但似乎没有起作用。 我将SelectionMode更改为Extended,但仍然不起作用。

我发现虽然它允许我使用 Control 和 Shift 选择多个项目,但我无法使用鼠标拖动来选择。我不确定其他人怎么想,但这对我来说确实是一个很大的惊喜。

奇怪的是,即使这是一个大问题,我也无法通过Google找到一个有用的/完整的解决方案来允许多重选择,所以我用我有限的 WPF 知识开发了这个组件。

我的设计过程

刚开始的时候,我试图找到每个ListViewItem的位置,并将其与所选区域进行比较; 我做了一些研究,但没有成功

  • 似乎没有一个通用的地方来存储哪个ListViewItem位于哪里,除非您开发了自己的Panel
  • 似乎可以重写TreeViewItemOnMouseMove,但这会将您的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 时的外观

2.jpg

历史

  • 05-02-08:初始版本(希望不是最后一个版本)。
  • 05-13-08:版本 2,修复了三个错误
    • 如果滚动条不可见,则无法拖动。
    • 拖动后出现奇怪的选择效果。
    • Shift+Select 未按预期工作。
© . All rights reserved.