QuickZipDev Workshop

Home‎ > ‎Articles‎ > ‎

MultiSelect ListView


This article is listed on CodeProject as well.

Introduction

This Article demos how to create a component that enable multiselect support for your Listview.

Background

I was developing a filelist, I didn't take much attention to selection mode, as I thought setting ListView.SelectionMode to Multiple/Extended will make the items in ListView by click and dragging. (thats my .Net 1.1 book told me).

Then when it's almost completed, I have time to do more test, unable to select more that one item is very annoying, so I set the selection mode to Multiple.

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

Recompile, It seems not working, no matter if I compile it a couple times, start dragging from empty space, change the SelectionMode to Extended, it simply not working.

I end up figured out although it allow me to select multiple items using Control and Shift, I cannot use mouse drag to select. I am not sure about other people, but this is really a big surprise for me.

It is wired that even though this is supposed a big common problem, I cannot Google a helpful / completed solution, allow multiple select is very important to my filelist, so I develop this component with my limited WPF knowledge.

My Design process

When I start, I tried to find the position of each ListViewItem and compare with select region, did some research but no luck :

  • There seems no common place to store which ListViewItem located in where, unless you developed your own Panel.
  • It seems possible to override OnMouseMove of TreeViewItem, but this will limit your ListView can use in StackPanel template only, as it require your mouse above the TreeViewItem. (See MultiSelectListView in demo project)
  • Arrange method expose size only, ArrangeCore method can expose a rect, but it is sealed.

After some Googling, I found a method named VisualTreeHelper.HitTest, which takes

  • a control,
  • a filter function, (retrive selected item via this func)
  • a result callback and
  • a rect.

and return child items in the specified rect.

It does what I wanted, but the HitTest method can return only the visible item, so if I start select, then scroll down, it will search only the items on screen, not the hidden items. This is then fixed by HitTest twice, first unselect all visible items, second select selected visible items.

//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)));

The last problem is to draw the preview rectangle, which is visible when selecting, as my knowledge is limited, all I can do is to draw it in background, please post if you have a better solution. (As you see, the preview rectangle cannot deal with Scrolling, I havent figured out how to obtain scrolling information yet)

lvSender.Background = new DrawingBrush(
DrawRectangle(selectRect, lvSender.ActualWidth, lvSender.ActualHeight));

Using the code

I have created a component for this operation, you can include the code in your project and set a Attached property to enable MultiSelect, you may have to set the ItemPanel Template so there is space for start dragging.
<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>

Setting the MultiSelect will attach 4 events to your ListView :
1. PreviewMouseDown, to clear selections.
2. MouseDown, to enable IsDragging attached property.
3. MouseUp, to disable IsDragging attached property.
4. MouseMove, if IsDragging, select the items.

How it looks when MultiSelect on my filelist

2.jpg

History

05-02-08 Initial version (hopefully not the last version)
05-13-08 Version 2, Fixed 3 Bugs :
- Cannot drag if Scrollbar not visible.
- Strange selection effect after drag.
- Shift+Select not work as intended.

09-07-08 Version 3
- Allow start dragging over an item (like fileexplorer in vista, ItemsPanelTemplate not required)
- handle scroll event to update selection. 

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License

Site Meter

Attachments (3)

  • MultiSelectListViewTest.zip - on May 2, 2008 1:26 AM by Leung Yat Chun Joseph (version 3 / earlier versions)
    50k Download
  • MultiSelectListViewTest2.zip - on May 17, 2008 5:46 AM by Leung Yat Chun Joseph (version 1)
    50k Download
  • MultiSelectListViewTest3.zip - on Sep 6, 2008 7:36 PM by Leung Yat Chun Joseph (version 1)
    3k Download