So the standard ListView located in the .NET Framework bothered me quite a lot yesterday.
We are using the ListView on a project to display a range of items that can be edited, when the user selects an item, the content of the item is shown on a pane to the right, he can then "unlock" it and make changes, but during this, if he decides to select another element in the list, we wanted to give him a dialog warning him about that his action would leave unsaved changes, and then give him 3 options.
- Save changes.
- Discard changes.
- Cancel the navigation.
Fairly simple, and very commonly used, the problem we had was that whenever one selects a new element in the list view, it fires the 2 related events "SelectedIndexChanged" and "ItemSelectionChanged" for each element that has changed, so in our case we first got the event raised for deselecting folowed by the event for the new selection.
Ultimately leading to a chain of dialogs. Our example is a bit more complicated than just that, with presentation models ect. but that is the basics.
Since i could not find any solutions on the web for this, that was acceptable (What we found was often based on timers, making the dialog only apear for every 2. event and so on), i enden up extending the listview.
This was actually fairly simple, and all in all, it works quite well. It includes 2 classes, the extented ListView and an EventArgs class.
CustomListView Class
1: public class CustomListView : ListView
2: {
3: public event EventHandler<CustomListViewSelectionChangedEventArgs> ListSelectionChanged;
4: private List<ListViewItem> selectedItems = new List<ListViewItem>();
5:
6: public void SelectItems(IEnumerable<ListViewItem> items)
7: {
8: List<ListViewItem> newSelection = new List<ListViewItem>(SelectedItems.Count);
9: foreach ( ListViewItem item in items )
10: newSelection.Add( item );
11:
12: List<ListViewItem> selected = newSelection.Except( selectedItems ).ToList();
13: List<ListViewItem> deselected = selectedItems.Except( newSelection ).ToList();
14:
15: foreach ( ListViewItem item in selected )
16: item.Selected = true;
17:
18: foreach ( ListViewItem item in deselected )
19: item.Selected = false;
20:
21: selectedItems = newSelection;
22: if ( selected.Count > 0 || deselected.Count > 0 )
23: {
24: OnListSelectionChanged(new CustomListViewSelectionChangedEventArgs(deselected.AsReadOnly(),selected.AsReadOnly()));
25: }
26: }
27:
28: protected override void OnMouseUp( MouseEventArgs e )
29: {
30: CheckSelectionChanges();
31: base.OnMouseUp( e );
32: }
33:
34: protected override void OnKeyUp( KeyEventArgs e )
35: {
36: CheckSelectionChanges();
37: base.OnKeyUp( e );
38: }
39:
40: protected virtual void OnListSelectionChanged( CustomListViewSelectionChangedEventArgs args )
41: {
42: if ( ListSelectionChanged != null )
43: {
44: ListSelectionChanged( this, args );
45: }
46: }
47:
48: private void CheckSelectionChanges()
49: {
50: List<ListViewItem> newSelection = new List<ListViewItem>( SelectedItems.Count );
51: foreach ( ListViewItem item in SelectedItems )
52: newSelection.Add( item );
53:
54: List<ListViewItem> selected = newSelection.Except( selectedItems ).ToList();
55: List<ListViewItem> deselected = selectedItems.Except( newSelection ).ToList();
56:
57: selectedItems = newSelection;
58: if ( selected.Count > 0 || deselected.Count > 0 )
59: {
60: OnListSelectionChanged( new CustomListViewSelectionChangedEventArgs( deselected.AsReadOnly(), selected.AsReadOnly() ) );
61: }
62: }
63: }
CustomListViewSelectionChangedEventArgs Class
1: public class CustomListViewSelectionChangedEventArgs : EventArgs
2: {
3: public IList<ListViewItem> Selected
4: {
5: get;
6: private set;
7: }
8:
9: public IList<ListViewItem> Deselected
10: {
11: get;
12: private set;
13: }
14:
15: public CustomListViewSelectionChangedEventArgs( IList<ListViewItem> deselected, IList<ListViewItem> selected )
16: {
17: Deselected = deselected;
18: Selected = selected;
19: }
20: }
Feel free to use.