diff --git a/ListViewEx.cs b/ListViewEx.cs new file mode 100644 index 00000000..aa1393ec --- /dev/null +++ b/ListViewEx.cs @@ -0,0 +1,182 @@ +//! \file ListViewEx.cs +//! \date Thu Jul 24 02:19:38 2014 +//! \brief Extended ListView with explorer-like multiple items selection. +// +// Copyright (C) 2014 by morkt +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// + +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Collections; +using System.Diagnostics; +using System.Linq; + +namespace GARbro.GUI +{ + /// + /// This Extended ListView allows selecting multiple items by dragging mouse over them. + /// + public class ListViewEx : ListView + { + public bool SelectionActive { get; set; } + public ListViewItem LastSelectedItem { get; set; } + + public ListViewEx () + { + } + + protected override DependencyObject GetContainerForItemOverride() + { + return new ListViewItemEx(); + } + + protected override void OnMouseLeftButtonDown (MouseButtonEventArgs e) + { + if (0 == (Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Shift))) + { + StartDragSelect(); + } + base.OnMouseLeftButtonDown (e); + } + + protected override void OnMouseLeftButtonUp (MouseButtonEventArgs e) + { + if (SelectionActive) + { + EndDragSelect(); + } + base.OnMouseLeftButtonUp (e); + } + + protected override void OnMouseLeave (MouseEventArgs e) + { + if (SelectionActive) + { + EndDragSelect(); + } + base.OnMouseLeave (e); + } + + protected override void OnItemsSourceChanged (IEnumerable oldValue, IEnumerable newValue) + { + if (SelectionActive) + { + EndDragSelect(); + } + base.OnItemsSourceChanged (oldValue, newValue); + } + + internal void StartDragSelect () + { + SelectionActive = true; + SelectedItems.Clear(); + } + + internal void EndDragSelect () + { + SelectionActive = false; + LastSelectedItem = null; + } + + internal void ContinueDragSelect (ListViewItem addition) + { + if (null != LastSelectedItem) + { + int start = ItemContainerGenerator.IndexFromContainer (LastSelectedItem); + int end = ItemContainerGenerator.IndexFromContainer (addition); + if (start != -1 && end != -1) + { + if (start > end) + { + int index = start; + start = end; + end = index; + } + // for each item in the range [start, end] + foreach (var item in Items.Cast().Skip (start).Take (end-start+1)) + { + var lvi = (ListViewItem)ItemContainerGenerator.ContainerFromItem (item); + if (!lvi.IsSelected) + lvi.IsSelected = true; + } + } + } + if (!addition.IsSelected) + addition.IsSelected = true; + LastSelectedItem = addition; + } + } + + class ListViewItemEx : ListViewItem + { + private ListViewEx ParentListView + { + get { return ItemsControl.ItemsControlFromItemContainer (this) as ListViewEx; } + } + + protected override void OnPreviewMouseLeftButtonDown (MouseButtonEventArgs e) + { + var lv = ParentListView; + if (null != lv) + { + if (0 == (Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Shift))) + { + lv.StartDragSelect(); + lv.ContinueDragSelect (this); + return; + } + } + base.OnPreviewMouseLeftButtonDown(e); + } + + protected override void OnPreviewMouseLeftButtonUp (MouseButtonEventArgs e) + { + var lv = ParentListView; + if (null != lv && lv.SelectionActive) + { + lv.EndDragSelect(); + } + base.OnPreviewMouseLeftButtonUp(e); + } + + protected override void OnMouseDoubleClick (MouseButtonEventArgs e) + { + var lv = ParentListView; + if (null != lv && lv.SelectionActive) + { + lv.EndDragSelect(); + } + base.OnMouseDoubleClick (e); + } + + protected override void OnMouseEnter (MouseEventArgs e) + { + var lv = ParentListView; + if (null != lv && lv.SelectionActive) + { + lv.ContinueDragSelect (this); + return; + } + base.OnMouseEnter (e); + } + } +} diff --git a/MainWindow.xaml b/MainWindow.xaml index dda8d3bc..c940e53e 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -150,7 +150,7 @@ - - +