2010-05-19 30 views
7

Solo me pregunto si alguien tiene alguna idea sobre cómo hacerlo. Quiero permitir que el usuario seleccione varios elementos haciendo clic y arrastrando el mouse (sin dejar que el clic salga). Supongamos que el usuario hace clic en el elemento 1, luego arrastra hacia abajo al elemento 10; los ítems del 1 al 10 deben seleccionarse como si hiciera clic en el ítem 1, luego cambiar + hacer clic en el ítem 10.wpf lista vista arrastrar seleccionar varios elementos

¡Déjenme saber gracias!

+0

Lo resuelto, voy a publicar la solución más adelante. Gracias. – Carlo

+0

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). –

Respuesta

9

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!

2

También tenga en cuenta que con SelectionMode=Extended esto ya es posible, si el usuario mantiene presionada la tecla SHIFT antes de presionar el botón del mouse.

2

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 MAYÚS 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 || e.Key == Key.RightShift) 
      { 
       SetIsDragSelectionEnabled(listBox, false); 
      } 
     } 

     private static void listBox_PreviewKeyUp(object sender, KeyEventArgs e) 
     { 
      var listBox = sender as ListBox; 
      if (listBox == null) 
       return; 

      if (e.Key == Key.LeftShift || e.Key == Key.RightShift) 
      { 
       SetIsDragSelectionEnabled(listBox, true); 
      } 
     } 

     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) 
     { 
      var listBox = obj as ListBox; 

      if (listBox == null) 
       return; 

      if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) 
       return; 

      var hitTestResult = VisualTreeHelper.HitTest(listBox, Mouse.GetPosition(listBox)); 
      if (hitTestResult == null) 
       return; 

      var element = hitTestResult.VisualHit; 
      while (element != null) 
      { 
       var scrollBar = element as ScrollBar; 
       if (scrollBar != null) 
       { 
        return; 
       } 
       element = VisualTreeHelper.GetParent(element); 
      } 

      if (GetIsDragClickStarted(listBox)) 
       listBox.SelectedItems.Clear(); 
     } 

     #endregion IsDragClickInitiatedProperty 
    } 
} 

Demostración: Demo

+0

¡Gracias! Fue casi una copia y pega, excepto el espacio de nombres modificado que generó errores (y la pequeña sección "clase parcial pública Ventana1: Ventana" al comienzo) – TripleAntigen

Cuestiones relacionadas