好的,这是我的解决方案,我创建了一个助手类来处理 ListView 的 PreviewLeftMouseButtonDown 和 MouseLeftButtonUp,并为 ListViewItems 创建了一个小样式,当鼠标悬停时它表示助手类,因此它可以决定是否选择项目与否(基于是否按下鼠标左键)。无论如何,这是完整的项目:
XAML:
<Window x:Class="DragSelectListBox.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DragSelectListBox"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="local:DragSelectionHelper.IsDragSelecting" Value="False" />
<Style.Triggers>
<Trigger Property="ListBoxItem.IsMouseOver" Value="True">
<Setter Property="local:DragSelectionHelper.IsDragSelecting" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid Background="AliceBlue">
<ListBox Margin="8"
local:DragSelectionHelper.IsDragSelectionEnabled="true">
<ListBoxItem Content="Item 1" />
<ListBoxItem Content="Item 2" />
<ListBoxItem Content="Item 3" />
<ListBoxItem Content="Item 4" />
<ListBoxItem Content="Item 5" />
<ListBoxItem Content="Item 6" />
<ListBoxItem Content="Item 7" />
<ListBoxItem Content="Item 8" />
<ListBoxItem Content="Item 9" />
<ListBoxItem Content="Item 10" />
<ListBoxItem Content="Item 11" />
<ListBoxItem Content="Item 12" />
<ListBoxItem Content="Item 13" />
<ListBoxItem Content="Item 14" />
<ListBoxItem Content="Item 15" />
<ListBoxItem Content="Item 16" />
<ListBoxItem Content="Item 17" />
<ListBoxItem Content="Item 18" />
<ListBoxItem Content="Item 19" />
<ListBoxItem Content="Item 20" />
<ListBoxItem Content="Item 21" />
<ListBoxItem Content="Item 22" />
<ListBoxItem Content="Item 23" />
<ListBoxItem Content="Item 24" />
<ListBoxItem Content="Item 25" />
<ListBoxItem Content="Item 26" />
<ListBoxItem Content="Item 27" />
<ListBoxItem Content="Item 28" />
<ListBoxItem Content="Item 29" />
<ListBoxItem Content="Item 30" />
</ListBox>
</Grid>
</Window>
C#:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace DragSelectListBox
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
// CARLO 20100519: Helper class for DragSelection
public class DragSelectionHelper : DependencyObject
{
#region Random Static Properties
// need a static reference to the listbox otherwise it can't be accessed
// (this only happened in the project I'm working on, if you're using a regular ListBox, with regular ListBoxItems you can get the ListBox from the ListBoxItems)
public static ListBox ListBox { get; private set; }
#endregion Random Static Properties
#region IsDragSelectionEnabledProperty
public static bool GetIsDragSelectionEnabled(DependencyObject obj)
{
return (bool)obj.GetValue(IsDragSelectionEnabledProperty);
}
public static void SetIsDragSelectionEnabled(DependencyObject obj, bool value)
{
obj.SetValue(IsDragSelectionEnabledProperty, value);
}
public static readonly DependencyProperty IsDragSelectionEnabledProperty =
DependencyProperty.RegisterAttached("IsDragSelectingEnabled", typeof(bool), typeof(DragSelectionHelper), new UIPropertyMetadata(false, IsDragSelectingEnabledPropertyChanged));
public static void IsDragSelectingEnabledPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
ListBox listBox = o as ListBox;
bool isDragSelectionEnabled = DragSelectionHelper.GetIsDragSelectionEnabled(listBox);
// if DragSelection is enabled
if (isDragSelectionEnabled)
{
// set the listbox's selection mode to multiple ( didn't work with extended )
listBox.SelectionMode = SelectionMode.Multiple;
// set the static listbox property
DragSelectionHelper.ListBox = listBox;
// and subscribe to the required events to handle the drag selection and the attached properties
listBox.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(DragSelectionHelper.listBox_PreviewMouseLeftButtonDown);
listBox.PreviewMouseRightButtonDown += new MouseButtonEventHandler(listBox_PreviewMouseRightButtonDown);
listBox.MouseLeftButtonUp += new MouseButtonEventHandler(DragSelectionHelper.listBox_MouseLeftButtonUp);
}
else // is selection is disabled
{
// set selection mode to the default
listBox.SelectionMode = SelectionMode.Single;
// dereference the listbox
DragSelectionHelper.ListBox = null;
// unsuscribe from the events
listBox.PreviewMouseLeftButtonDown -= new MouseButtonEventHandler(DragSelectionHelper.listBox_PreviewMouseLeftButtonDown);
listBox.MouseLeftButtonUp -= new MouseButtonEventHandler(DragSelectionHelper.listBox_MouseLeftButtonUp);
listBox.MouseLeftButtonUp -= new MouseButtonEventHandler(DragSelectionHelper.listBox_MouseLeftButtonUp);
}
}
static void listBox_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
// to prevent the listbox from selecting / deselecting wells on right click
e.Handled = true;
}
private static void listBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// notify the helper class that the listbox has initiated the drag click
DragSelectionHelper.SetIsDragClickStarted(DragSelectionHelper.ListBox, true);
}
private static void listBox_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
// notify the helper class that the list box has terminated the drag click
DragSelectionHelper.SetIsDragClickStarted(DragSelectionHelper.ListBox, false);
}
#endregion IsDragSelectionEnabledProperty
#region IsDragSelectinProperty
public static bool GetIsDragSelecting(DependencyObject obj)
{
return (bool)obj.GetValue(IsDragSelectingProperty);
}
public static void SetIsDragSelecting(DependencyObject obj, bool value)
{
obj.SetValue(IsDragSelectingProperty, value);
}
public static readonly DependencyProperty IsDragSelectingProperty =
DependencyProperty.RegisterAttached("IsDragSelecting", typeof(bool), typeof(DragSelectionHelper), new UIPropertyMetadata(false, IsDragSelectingPropertyChanged));
public static void IsDragSelectingPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
ListBoxItem item = o as ListBoxItem;
bool clickInitiated = DragSelectionHelper.GetIsDragClickStarted(DragSelectionHelper.ListBox);
// this is where the item.Parent was null, it was supposed to be the ListBox, I guess it's null because items are not
// really ListBoxItems but are wells
if (clickInitiated)
{
bool isDragSelecting = DragSelectionHelper.GetIsDragSelecting(item);
if (isDragSelecting)
{
// using the ListBox static reference because could not get to it through the item.Parent property
DragSelectionHelper.ListBox.SelectedItems.Add(item);
}
}
}
#endregion IsDragSelectinProperty
#region IsDragClickStartedProperty
public static bool GetIsDragClickStarted(DependencyObject obj)
{
return (bool)obj.GetValue(IsDragClickStartedProperty);
}
public static void SetIsDragClickStarted(DependencyObject obj, bool value)
{
obj.SetValue(IsDragClickStartedProperty, value);
}
public static readonly DependencyProperty IsDragClickStartedProperty =
DependencyProperty.RegisterAttached("IsDragClickStarted", typeof(bool), typeof(DragSelectionHelper), new UIPropertyMetadata(false, IsDragClickStartedPropertyChanged));
public static void IsDragClickStartedPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
bool isDragClickStarted = DragSelectionHelper.GetIsDragClickStarted(DragSelectionHelper.ListBox);
// if click has been drag click has started, clear the current selected items and start drag selection operation again
if (isDragClickStarted)
DragSelectionHelper.ListBox.SelectedItems.Clear();
}
#endregion IsDragClickInitiatedProperty
}
}
如您所见,您需要做的就是在您的 xaml 中添加样式,然后设置:
local:DragSelectionHelper.IsDragSelectionEnabled="true"
ListView 的附加属性,它会处理所有事情。
谢谢!