2010-05-19 10 views
7

Ich frage mich nur, ob jemand eine Idee hat, wie man das macht. Ich möchte den Benutzer durch Klicken und Ziehen der Maus mehrere Objekte auswählen lassen (ohne den Klick loszulassen). Sagen Sie, der Benutzer klickt auf Element 1 und dann auf Element 10; Die Punkte 1 bis 10 sollten ausgewählt werden, als ob er auf Punkt 1 geklickt hätte, dann auf Punkt 10 verschoben und geklickt.wpf listview ziehen mehrere Elemente auswählen

Lassen Sie mich dank!

+0

ich es gelöst, ich werde die Lösung Post später. Vielen Dank. – Carlo

+0

Ich habe eine neue Lösung für diese Frage an [WPF Drag & Drop von ListBox mit SelectionMode Mehrere] (http://StackOverflow.com/questions/1553622/wpf-drag-drop-from-listbox-with-selectionmode) gepostet -mehrere). –

Antwort

9

Ok, hier ist meine Lösung, ich habe eine Hilfsklasse erstellt, die die PreviewLeftMouseButtonDown und MouseLeftButtonUp für die ListView behandelt, und einen kleinen Stil für die ListViewItems, die nach dem Mausklick die Hilfsklasse angibt, damit sie entscheiden kann, ob sie selektiert das Objekt oder nicht (basierend auf der linken Maustaste gedrückt oder nicht). Wie auch immer, hier ist das komplette Projekt:

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 
    } 
} 

So wie Sie sehen können, alles, was Sie tun müssen, um den Stil in Ihrem XAML hinzufügen und Satz das:

local: DragSelectionHelper.IsDragSelectionEnabled = "true"

angebaute Eigenschaft auf die L istView, und das wird sich um alles kümmern.

Danke!

2

Beachten Sie auch, dass dies mit SelectionMode=Extended bereits möglich ist, wenn der Benutzer den Schlüssel SHIFT vor der Maustaste gedrückt hält.

2

Basierend auf Carlos Antwort habe ich einen Teil seines Codes geändert, jetzt können Sie mit CTRL weiter auswählen, ohne die aktuelle Auswahl zu löschen, und mit der UMSCHALTTASTE Elemente wie den erweiterten Modus auswählen.

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 
    } 
} 

Demo: Demo

+0

Danke! Es war fast ein Kopieren und Einfügen mit Ausnahme des geänderten Namespaces, der Fehler verursachte (und der kleine Abschnitt "öffentliche Teilklasse Window1: Window" am Anfang) – TripleAntigen