Ok, esta es mi solución, creé una clase auxiliar que maneja PreviewLeftMouseButtonDown y MouseLeftButtonUp para ListView y un pequeño estilo para los ListViewItems que cuando el mouse termina indica la clase auxiliar, por lo que puede decidir si selecciona el elemento o no (basado en el botón izquierdo del mouse que se está presionando o no). De todos modos, aquí está el proyecto completo:
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
}
}
Así como se puede ver, todo lo que necesita hacer es añadir el estilo en su xaml, y un conjunto el:
locales: DragSelectionHelper.IsDragSelectionEnabled = "true"
propiedad adjunta a la L istView, y eso se encargará de todo.
Gracias!
Lo resuelto, voy a publicar la solución más adelante. Gracias. – Carlo
He publicado una nueva solución a esta pregunta en [WPF Arrastrar y soltar desde ListBox con SelectionMode Multiple] (http://stackoverflow.com/questions/1553622/wpf-drag-drop-from-listbox-with-selectionmode -múltiple). –