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

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