2013-07-02 28 views
17

Tôi có một DataGrid và không thích workaround của mình để kích hoạt lệnh double click trên viewmodel của tôi cho hàng được nhấp (aka selected).Bind Lệnh DoubleClick từ DataGrid Row đến VM

Xem:

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

Tôi muốn thoát khỏi quan điểm liên quan đến mã (một với đối tượng phụ thuộc và cây helper hình ảnh) trong mô hình quan điểm của tôi, vì điều này phá vỡ khả năng thử nghiệm bằng cách nào đó. Nhưng mặt khác theo cách này, tôi tránh điều gì đó xảy ra khi người dùng không nhấp vào một hàng nhưng trên tiêu đề chẳng hạn.

PS: Tôi đã thử xem xét các hành vi đính kèm, nhưng tôi không thể tải xuống từ Skydrive tại nơi làm việc, vì vậy giải pháp 'được tích hợp sẵn' sẽ là tốt nhất.

Trả lời

23

Tại sao bạn không chỉ cần sử dụng 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> 

lệnh của bạn là một cái gì đó như thế này:

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

     return mouseDoubleClickCommand; 
    } 
} 

EDIT: bây giờ tôi sử dụng này thay vì Interaction.Triggers:

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

Vấn đề không nhận được các mục được chọn (nó là databound dù sao trên máy ảo), nhưng nhận lệnh không được thực thi khi, ví dụ, các tiêu đề của DataGrid được DoubleClick. – metacircle

+2

nếu bạn muốn ngăn chặn mousedoubleclick bạn có thể thử PreviewMouseDoubleClick và đặt e.Handled = true cho các điều kiện của bạn. vì vậy bạn có thể mở lại mã từ viewmodel và đặt nó trong codebehind cho datagrid của bạn – blindmeis

+0

Ý tưởng tuyệt vời. Trên thực tế tôi đã làm điều tương tự trong codebehind của tôi cho OnContextMenuOpening tất cả cùng. Đôi khi bạn không có ý tưởng đúng vào đúng thời điểm. Cảm ơn. Tôi sẽ đánh dấu điều này là câu trả lời. – metacircle

0

Bạn có thể thử cách này:

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

Trong trường hợp này, bạn phải xác định DataTemplate cho mỗi cột trong DataGrid

+0

Tôi đoán đây sẽ làm việc, nhưng nếu tôi phải lựa chọn giữa điều này và cách giải quyết của tôi, tôi có lẽ sẽ gắn bó với tôi. Nếu tôi thay đổi cột, tôi luôn phải lặp lại mã XAML của bạn cho mỗi cột. – metacircle

11

Đây là cách bạn có thể thực hiện nó bằng một hành vi kèm theo:

CHỈNH SỬA: Hiện hành vi đăng ký trên DataGridRow thay vì DataGrid để DataGridHeader nhấp chuột bị bỏ qua ored.

Hành vi:

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> 

Sau đó bạn sẽ cần phải sửa đổi MouseDoubleClickCommand của bạn để loại bỏ các tham số MouseButtonEventArgs và thay thế bằng loại SelectedItem của bạn.

+0

Tôi thích điều này như là một giải pháp gần như hoàn hảo (đọc là tốt nhất).Sau đây là những gì các sự kiện attched có nghĩa là: http://www.codeproject.com/Articles/28959/Introduction-to-Attached-Behaviors-in-WPF – James

7

Way đơn giản hơn so với bất kỳ của các giải pháp đề xuất ở đây.

Tôi đang sử dụng cái này.

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

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

+0

Cảm ơn bạn về nguồn liên kết ban đầu - nó rất hữu ích. Để những người khác đọc nhận xét này: hãy đặc biệt chú ý đến dấu gạch chéo ở cuối giá trị thuộc tính của CommandParameter (ví dụ: "SearchItems /"). –