2010-07-16 26 views
5

Ho un oggetto listview contenente i file nel programma. Il comportamento listview predefinito mi consente di eseguire tutte le operazioni di selezione nell'elenco (fai clic su + Maiusc per selezionare un blocco, fai clic su + ctrl per selezionare individualmente i membri di un gruppo di elementi e fai clic per selezionare un singolo elemento).WPF listview trascinare senza deselezionare

Voglio iniziare a trascinare questi elementi con un clic e tenere premuto il pulsante sinistro del mouse, ma deseleziona gli elementi ... e anche mentre il mouse si muove, selezionerà qualsiasi cosa il mouse sia finito. Come gestisco gli eventi del mouse per consentire normalmente la selezione predefinita, ma non selezionare/deselezionare se l'elemento viene trascinato?

Se gestisco l'evento di clic giù, la modifica della selezione avviene contemporaneamente ... è solo quando inizia il trascinamento mentre il clic è ancora inattivo che so che si tratta di un trascinamento della selezione rispetto a una selezione.

Ecco il codice XAML di base per il controllo ...

<Window.Resources> 
    <Style x:Key="itemstyle" TargetType="{x:Type ListViewItem}"> 
     <EventSetter Event="PreviewMouseDown" Handler='listView2_MouseLeftButtonDown'/> 
    </Style> 
</Window.Resources> 


<ListView Grid.Column="0" Grid.Row="1" Name="listView2" Margin="5,5,5,5" BorderBrush="LightGray" AllowDrop="True" Drop="listView2_Drop" ItemsSource="{Binding}" ItemContainerStyle="{StaticResource itemstyle}"> 
       <ListView.View> 
        <GridView> 
         <GridViewColumn Header="Name" Width="100"> 
          <GridViewColumn.CellTemplate> 
           <DataTemplate> 
            <StackPanel Orientation="Horizontal"> 
             <Image Source="{Binding Bmp}"/> 
             <TextBlock Text="{Binding Name}"/> 
            </StackPanel> 
           </DataTemplate> 
          </GridViewColumn.CellTemplate> 
         </GridViewColumn> 
         <GridViewColumn Header="Ext" DisplayMemberBinding="{Binding Ext}" Width="Auto"/> 
         <GridViewColumn Header="Size" DisplayMemberBinding="{Binding Size}" Width="Auto"/> 
         <GridViewColumn Header="Date" DisplayMemberBinding="{Binding Date}" Width="Auto"/> 
        </GridView> 
       </ListView.View> 
      </ListView> 

Ok, così sono andato con la gestione il mouse PreviewMouseDown e visualizzare in anteprima gli eventi ... se un tasto di controllo o turno viene premuto, non imposto il flag di handle ... ma altrimenti imposto l'argomento gestito su true (quindi le modifiche alla selezione non avvengono) Quindi sull'evento previewmouseup, completo la selezione singola impostando "selected" valore su true (di nuovo solo quando si preme shift o ctrl). Quindi questo funziona ... ma la selezione del blocco maiuscole non usa alcun elemento che seleziono programmaticamente come punto di partenza valido per la selezione, invece di andare al primo elemento cliccato usando un tasto Maiusc o Ctrl (anche se io ' ha eliminato manualmente tutti gli elementi selezionati).

Qui è la fonte:

private void listView2_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
    { 
     if (e.LeftButton == MouseButtonState.Pressed) 
     { 
      if (!Keyboard.IsKeyDown(Key.LeftCtrl) && 
       !Keyboard.IsKeyDown(Key.RightCtrl) && 
       !Keyboard.IsKeyDown(Key.LeftShift) && 
       !Keyboard.IsKeyDown(Key.RightShift)) 
      { 
       e.Handled = true; 
      } 
     } 
    } 

    private void listView2_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 
    { 
     if (e.ChangedButton == MouseButton.Left) 
     { 
      if (!Keyboard.IsKeyDown(Key.LeftCtrl) && 
       !Keyboard.IsKeyDown(Key.RightCtrl) && 
       !Keyboard.IsKeyDown(Key.LeftShift) && 
       !Keyboard.IsKeyDown(Key.RightShift)) 
      { 

       listView2.SelectedItems.Clear(); 
       ListViewItem lvi = sender as ListViewItem; 
       listView2.SelectedItem = lvi; 
       lvi.IsSelected = true; 
       e.Handled = true; 
      } 
     } 
    } 

risposta

0

avuto lo stesso problema con il TreeView di controllo non molto tempo fa ... ecco come ho lavorato intorno alla questione:

private void TreeViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
{ 
    // skip mouse clicks on the expander button 
    if (e.Source is ToggleButton) 
     return; 

    // find the original source's parent TreeViewItem 
    DependencyObject originalSource = e.OriginalSource as DependencyObject; 
    while (originalSource != null) 
    { 
     TreeViewItem tvi = originalSource as TreeViewItem; 
     if (tvi != null) 
     { 
      IListItem listItem = tvi.Header as IListItem; 
      if (listItem != null) 
      { 
       if (Keyboard.Modifiers == ModifierKeys.Shift) 
        ViewModel.MultiSelectTo(listItem); 
       else if (Keyboard.Modifiers == ModifierKeys.Control) 
        ViewModel.ToggleSelection(listItem); 
       else 
        ViewModel.Select(listItem); 
      } 

      // the TreeViewItem is never truly selected... when selected, we manually change it's background color (see xaml) 
      tvi.IsSelected = false; 
      e.Handled = true; 
      break; 
     } 

     originalSource = VisualTreeHelper.GetParent(originalSource); 
    } 
} 

XAML:

<Style.Triggers> 
<DataTrigger Binding="{Binding Selected}" Value="True"> 
    <Setter Property="Background" Value="#FF3399FF" /> 
</DataTrigger> 
</Style.Triggers> 


L'interfacciaè l'interfaccia che i miei oggetti dati implementano per essere mostrata nel mio TreeView. La proprietà ViewModel è la mia vista DataContext. Inoltre, il seguente commento è importante "l'oggetto TreeViewItem non è mai veramente selezionato ... quando selezionato, cambiamo manualmente il suo colore di sfondo (vedi xaml)".

Quindi, in sostanza, ciò che ho fatto è rimuovere la gestione della selezione dal controllo TreeView per gestirlo da solo.

Spero che questo aiuti in qualsiasi modo ...