2013-07-02 11 views
17

Mam Datagrid i nie podoba mi się moje obejście, aby uruchomić polecenie dwukrotnego kliknięcia w moim modelu widoku dla klikniętego (oznaczonego aka) wiersza.Powiąż polecenie DoubleClick z wiersza DataGrid do VM

Widok:

<DataGrid EnableRowVirtualization="True" 
       ItemsSource="{Binding SearchItems}" 
       SelectedItem="{Binding SelectedItem}" 
       SelectionMode="Single" 
       SelectionUnit="FullRow"> 

     <i:Interaction.Triggers> 
      <i:EventTrigger EventName="MouseDoubleClick"> 
       <cmd:EventToCommand Command="{Binding MouseDoubleClickCommand}" PassEventArgsToCommand="True" /> 
      </i:EventTrigger> 
     </i:Interaction.Triggers> 
     ... 
    </DataGrid> 

ViewModel:

public ICommand MouseDoubleClickCommand 
    { 
     get 
     { 
      if (mouseDoubleClickCommand == null) 
      { 
       mouseDoubleClickCommand = new RelayCommand<MouseButtonEventArgs>(
        args => 
        { 
         var sender = args.OriginalSource as DependencyObject; 
         if (sender == null) 
         { 
          return; 
         } 
         var ancestor = VisualTreeHelpers.FindAncestor<DataGridRow>(sender); 
         if (ancestor != null) 
         { 
          MessengerInstance.Send(new FindDetailsMessage(this, SelectedItem.Name, false)); 
         } 
        } 
        ); 
      } 
      return mouseDoubleClickCommand; 
     } 
    } 

Chcę pozbyć się widoku związane kodu (jednego z obiektem zależnościach i wizualne drzewo pomocnika) w moim modelu widoku, jak to w jakiś sposób psuje sprawność. Ale z drugiej strony unikam tego, że coś się dzieje, gdy użytkownik nie kliknie wiersza, ale na przykład w nagłówku.

PS: Próbowałem rzucić okiem na załączone zachowania, ale nie mogę pobrać ze Skydrive w pracy, więc najlepiej byłoby "wbudowane" rozwiązanie.

Odpowiedz

23

Dlaczego po prostu nie używasz CommandParameter?

<DataGrid x:Name="myGrd" 
      ItemsSource="{Binding SearchItems}" 
      SelectedItem="{Binding SelectedItem}" 
      SelectionMode="Single" 
      SelectionUnit="FullRow"> 

    <i:Interaction.Triggers> 
     <i:EventTrigger EventName="MouseDoubleClick"> 
      <cmd:EventToCommand Command="{Binding MouseDoubleClickCommand}" 
           CommandParameter="{Binding ElementName=myGrd, Path=SelectedItem}" /> 
     </i:EventTrigger> 
    </i:Interaction.Triggers> 
    ... 
</DataGrid> 

Twoje polecenie jest coś takiego:

public ICommand MouseDoubleClickCommand 
{ 
    get 
    { 
     if (mouseDoubleClickCommand == null) 
     { 
      mouseDoubleClickCommand = new RelayCommand<SearchItem>(
       item => 
       { 
        var selectedItem = item; 
       }); 
     } 

     return mouseDoubleClickCommand; 
    } 
} 

EDIT: I teraz to wykorzystać zamiast Interaction.Triggers:

<DataGrid.InputBindings> 
    <MouseBinding MouseAction="LeftDoubleClick" 
        Command="{Binding Path=MouseDoubleClickCommand}" 
        CommandParameter="{Binding ElementName=myGrd, Path=SelectedItem}" /> 
</DataGrid.InputBindings> 
+1

Problem nie polega na pobraniu wybranego elementu (jest to databound tak czy inaczej na maszynie wirtualnej), ale uzyskanie polecenia, aby nie wykonywać, gdy na przykład nagłówki datagridu są klikane podwójnie. – metacircle

+2

jeśli chcesz zapobiec mousedoubleclick możesz spróbować PreviewMouseDoubleClick i ustawić e.Handled = true dla twoich warunków. dzięki czemu można przeobrazić kod z viewmodel i umieścić go w codebehind dla swojego datagrid – blindmeis

+0

Świetny pomysł. Właściwie robiłem to samo w moim kodzie dla OnContextMenuOpening cały czas. Czasami po prostu nie masz odpowiednich pomysłów we właściwym czasie. Dzięki. Zaznaczę to jako odpowiedź. – metacircle

0

Możesz spróbować tego rozwiązania:

<DataGrid EnableRowVirtualization="True" 
      ItemsSource="{Binding SearchItems}" 
      SelectedItem="{Binding SelectedItem}" 
      SelectionMode="Single" 
      SelectionUnit="FullRow"> 
    <DataGrid.Columns> 
     <DataGridTemplateColumn Header="....."> 
      <DataGridTemplateColumn.CellTemplate> 
       <DataTemplate> 
         <TextBlock .....> 
          <i:Interaction.Triggers> 
           <i:EventTrigger EventName="MouseDoubleClick"> 
            <cmd:EventToCommand Command="{Binding MouseDoubleClickCommand}" PassEventArgsToCommand="True" /> 
           </i:EventTrigger> 
          </i:Interaction.Triggers> 
         </TextBlock> 
       </DataTemplate> 
    ................... 

W tym przypadku trzeba określić DataTemplate dla każdej kolumny w DataGrid

+0

Myślę, że to będzie działać, ale jeśli miałbym wybierać między nim a moim obejściu, to pewnie trzymać się z kopalni. Jeśli zmienię kolumny, zawsze będę musiał powtórzyć Twój kod XAML dla każdej kolumny. – metacircle

11

Oto jak można go realizować przy użyciu załączonego zachowanie:

EDYTOWANIE: Teraz rejestruje zachowanie na DataGridRow zamiast DataGrid, dzięki czemu DataGridHeader kliknięć jest ign ored.

Zachowanie:

public class Behaviours 
{ 
    public static DependencyProperty DoubleClickCommandProperty = 
     DependencyProperty.RegisterAttached("DoubleClickCommand", typeof(ICommand), typeof(Behaviours), 
              new PropertyMetadata(DoubleClick_PropertyChanged)); 

    public static void SetDoubleClickCommand(UIElement element, ICommand value) 
    { 
     element.SetValue(DoubleClickCommandProperty, value); 
    } 

    public static ICommand GetDoubleClickCommand(UIElement element) 
    { 
     return (ICommand)element.GetValue(DoubleClickCommandProperty); 
    } 

    private static void DoubleClick_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var row = d as DataGridRow; 
     if (row == null) return; 

     if (e.NewValue != null) 
     { 
      row.AddHandler(DataGridRow.MouseDoubleClickEvent, new RoutedEventHandler(DataGrid_MouseDoubleClick)); 
     } 
     else 
     { 
      row.RemoveHandler(DataGridRow.MouseDoubleClickEvent, new RoutedEventHandler(DataGrid_MouseDoubleClick)); 
     } 
    } 

    private static void DataGrid_MouseDoubleClick(object sender, RoutedEventArgs e) 
    { 
     var row= sender as DataGridRow; 

     if (row!= null) 
     { 
      var cmd = GetDoubleClickCommand(row); 
      if (cmd.CanExecute(row.Item)) 
       cmd.Execute(row.Item); 
     } 
    } 
} 

Xaml:

<DataGrid x:Name="grid" EnableRowVirtualization="True" 
      SelectedItem="{Binding SelectedItem}" 
      SelectionMode="Single" 
      SelectionUnit="FullRow" ItemsSource="{Binding SearchItems}"> 
     <DataGrid.RowStyle> 
      <Style TargetType="DataGridRow"> 
       <Setter Property="Behaviours.DoubleClickCommand" Value="{Binding ElementName=grid, Path=DataContext.SortStateCommand}"/> 
      </Style> 
     </DataGrid.RowStyle> 

Następnie należy zmodyfikować MouseDoubleClickCommand usunąć parametr MouseButtonEventArgs i zastąpić go swoim rodzaju SelectedItem.

+0

Podoba mi się to jako idealne rozwiązanie (czytaj to najlepiej).Poza tym jest to przeznaczone na następujące zdarzenia: http://www.codeproject.com/Articles/28959/Introduction-to-Attached- Bee-in-w-WPF – James

7

sposób prostszy niż którykolwiek z tutejszych proponowanych rozwiązań.

Używam tego.

<!-- 
requires IsSynchronizedWithCurrentItem 
for more info on virtualization/perf https://stackoverflow.com/questions/9949358/datagrid-row-virtualization-display-issue 
--> 
     <DataGrid ItemsSource="{Binding SearchItems}" 
        IsSynchronizedWithCurrentItem="True" 
        AutoGenerateColumns="false" CanUserAddRows="False" CanUserDeleteRows="False" IsReadOnly="True" EnableRowVirtualization="True" 
        > 

      <!-- for details on ICollection view (the magic behind {Binding Accounts/} https://marlongrech.wordpress.com/2008/11/22/icollectionview-explained/ --> 

      <DataGrid.InputBindings> 
       <MouseBinding 
        MouseAction="LeftDoubleClick" 
        Command="{Binding MouseDoubleClickCommand}" 
        CommandParameter="{Binding SearchItems/}" /> 
      </DataGrid.InputBindings> 
     </DataGrid> 

z WPF DataGrid: CommandBinding to a double click instead of using Events

+0

Dziękujemy za początkowe źródło linku - było użyteczne. Inni, którzy czytają ten komentarz: zwracają szczególną uwagę na ukośnik w przód na końcu wartości atrybutu CommandParameter (np. "SearchItems /"). –

Powiązane problemy