Hemos estado buscando por diferentes espacios para así mostrarte la solución para tu duda, si continúas con inquietudes déjanos la inquietud y contestamos porque estamos para ayudarte.
Solución:
Ok, aquí está mi solución, creé una clase auxiliar que maneja PreviewLeftMouseButtonDown y MouseLeftButtonUp para ListView, y un estilo pequeño para ListViewItems que cuando el mouse está sobre indica la clase auxiliar, por lo que puede decidir si selecciona el elemento o no (basado en que se presione o no el botón izquierdo del mouse). De todos modos, aquí está el proyecto completo:
XAML:
C#:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace DragSelectListBox
///
/// Interaction logic for Window1.xaml
///
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
Como puede ver, todo lo que necesita hacer es agregar el estilo en su xaml y establecer:
local: DragSelectionHelper.IsDragSelectionEnabled = “true”
Propiedad adjunta a ListView, y eso se encargará de todo.
¡Gracias!
Basado en la respuesta de Carlo, modifiqué parte de su código, ahora puede usar CTRL para continuar seleccionando sin borrar la selección actual, y usar SHIFT para seleccionar elementos como el modo ‘Extendido’.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
namespace SteamFriendsManager.Utility
public class DragSelectionHelper : DependencyObject
#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));
private static void IsDragSelectingEnabledPropertyChanged(DependencyObject o,
DependencyPropertyChangedEventArgs e)
var listBox = o as ListBox;
if (listBox == null)
return;
// if DragSelection is enabled
if (GetIsDragSelectionEnabled(listBox))
// set the listbox's selection mode to multiple ( didn't work with extended )
listBox.SelectionMode = SelectionMode.Multiple;
// and subscribe to the required events to handle the drag selection and the attached properties
listBox.PreviewMouseRightButtonDown += listBox_PreviewMouseRightButtonDown;
listBox.PreviewMouseLeftButtonDown += listBox_PreviewMouseLeftButtonDown;
listBox.PreviewMouseLeftButtonUp += listBox_PreviewMouseLeftButtonUp;
listBox.PreviewKeyDown += listBox_PreviewKeyDown;
listBox.PreviewKeyUp += listBox_PreviewKeyUp;
else // is selection is disabled
// set selection mode to the default
listBox.SelectionMode = SelectionMode.Extended;
// unsuscribe from the events
listBox.PreviewMouseRightButtonDown -= listBox_PreviewMouseRightButtonDown;
listBox.PreviewMouseLeftButtonDown -= listBox_PreviewMouseLeftButtonDown;
listBox.PreviewMouseLeftButtonUp -= listBox_PreviewMouseLeftButtonUp;
listBox.PreviewKeyDown -= listBox_PreviewKeyDown;
listBox.PreviewKeyUp += listBox_PreviewKeyUp;
private static void listBox_PreviewKeyDown(object sender, KeyEventArgs e)
var listBox = sender as ListBox;
if (listBox == null)
return;
if (e.Key == Key.LeftShift
private static void listBox_PreviewKeyUp(object sender, KeyEventArgs e)
var listBox = sender as ListBox;
if (listBox == null)
return;
if (e.Key == Key.LeftShift
private 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)
SetIsDragClickStarted(sender as DependencyObject, true);
private static void listBox_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
SetIsDragClickStarted(sender as DependencyObject, false);
public static DependencyObject GetParent(DependencyObject obj)
if (obj == null)
return null;
var ce = obj as ContentElement;
if (ce == null) return VisualTreeHelper.GetParent(obj);
var parent = ContentOperations.GetParent(ce);
if (parent != null)
return parent;
var fce = ce as FrameworkContentElement;
return fce != null ? fce.Parent : null;
#endregion IsDragSelectionEnabledProperty
#region IsDragSelectingProperty
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));
private static void IsDragSelectingPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
var listBoxItem = o as ListBoxItem;
if (listBoxItem == null)
return;
if (!GetIsDragClickStarted(listBoxItem)) return;
if (GetIsDragSelecting(listBoxItem))
listBoxItem.IsSelected = true;
#endregion IsDragSelectingProperty
#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 FrameworkPropertyMetadata(false, IsDragClickStartedPropertyChanged) Inherits = true);
private static void IsDragClickStartedPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
#endregion IsDragClickInitiatedProperty
Manifestación:
También tenga en cuenta que con SelectionMode=Extended
esto ya es posible, si el usuario mantiene presionada la CAMBIO antes de presionar el botón del mouse.
Nos encantaría que puedieras dar visibilidad a este enunciado si te ayudó.