Click here to Skip to main content
Click here to Skip to main content

Enable MultiSelect in WPF ListView

By , 12 May 2008
 

Introduction

This article demos how to create a component that enables multi-select support for your ListView.

Background

I was developing a file list, and I didn't pay much attention to the selection mode as I thought setting ListView.SelectionMode to Multiple/Extended will select multiple items in a ListView by clicking and dragging. (That's what my .NET 1.1 book told me.)

Then, when it was almost completed, I had the time to do more tests, and was unable to select more that one item. This was very annoying, so I set the SelectionMode to Multiple.

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

I recompile and it did not seem to work. I changed the SelectionMode to Extended, and it still was not working.

I figured out that although it allowed me to select multiple items using Control and Shift, I could not use mouse drag to select. I am not sure about others, but this is really a big surprise for me.

It was weird that even though this was a big problem, I could not Google and get a helpful / completed solution that allowed multiple selects, so I developed this component with my limited WPF knowledge.

My design process

When I started, I tried to find the position of each ListViewItem and compare that with the selected region; I did some research but with no luck:

  • There seems to be no common place to store which ListViewItem is located where, unless you developed your own Panel.
  • It seems possible to override OnMouseMove of TreeViewItem, but this will limit your ListView to be used in a StackPanel template only, as it requires your mouse above the TreeViewItem. (See the MultiSelectListView in the demo project.)
  • The Arrange method exposes the size only, the 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, (retrieve the selected item via this func)
  • a result callback, and
  • a rect.

and returns 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 selecting, then scroll down, it will search only the items on the screen, not the hidden items. This is then fixed by HitTest twice, first by unselecting all the visible items, and then selecting the 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 the background. Please post if you have a better solution. (As you can see, the preview rectangle cannot deal with scrolling; I haven't figured out how to obtain the 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 an Attached property to enable multi-select. You may have to set the ItemPanel Template so there is space for starting the 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 four events to your ListView:

  • PreviewMouseDown, to clear selections.
  • MouseDown to enable the IsDragging attached property.
  • MouseUp to disable the IsDragging attached property.
  • MouseMove, if IsDragging, selects the items.

How it looks when MultiSelect is enabled on my file list

2.jpg

History

  • 05-02-08: Initial version (hopefully not the last version).
  • 05-13-08: Version 2, fixed three bugs:
    • Cannot drag if scrollbar not visible.
    • Strange selection effect after drag.
    • Shift+Select not working as intended.

License

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

About the Author

Leung Yat Chun
Software Developer
Hong Kong Hong Kong
Member

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalthank youmembervikinl12 Aug '11 - 22:36 
I was having the same problem. This gives me an idea to work on.
Smile | :)
thank you guys
NewsImportant note for reader.memberLeung Yat Chun5 May '10 - 11:06 
Thanks for reading my article, but :
 
Please noted that after two years, I have released a improved version of the component here :
Enable MultiSelect in WPF ListView (2)[^]
 
It uses a different method to do the selection work to provide better performance.
This version will not be updated anymore.
 
A FileExplorer is written using the new component, can be found here :
WPF x FileExplorer x MVVM[^]
 

Regards
Joseph Leung

GeneralMy vote of 2memberMickey Mousoff7 Jan '10 - 6:04 
Is overly complicated and Does not really work.
GeneralRe: My vote of 2 [modified]memberLeung Yat Chun10 Mar '10 - 21:36 
The approach above is what I developed 2 years ago without sufficient knowledge.
But dont worry, after 2 years I have *just* completed another approach that works better.
 
I rewrite and coded the following :
 
Adorner (SelectionAdorner)
Panel (VirtualStackPanel, VirtualWrapPanel)
ViewBase (VirtualStackPanelView, VirtualWrapPanelView)
and the new SelectionHelper class.
 
I am preparing the new article now, a screenshot is shown below.
http://picasaweb.google.com/lh/photo/WhIvyMwEMmxQBALT5e_DSg?feat=directlink[^]
 
And yes, it aware the scroll position now.
QuickZip
modified on Thursday, March 11, 2010 4:13 AM

GeneralThank you!memberLukas Fellechner12 Dec '08 - 4:43 
Just wanted to say thanks for the code sample! The HitTest trick was really useful for me, I've been searching for a good Listview drag selection mechanism for quite some time...
 
Best regards
Lukas

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 13 May 2008
Article Copyright 2008 by Leung Yat Chun
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid