将DoubleClick命令从DataGrid行绑定到VM

met*_*cle 20 wpf binding datagrid command mvvm

我有一个Datagrid,并且不喜欢我的解决方法在我的viewmodel上为单击的(也就是选定的)行触发双击命令.

视图:

   <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>
Run Code Online (Sandbox Code Playgroud)

视图模型:

    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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

我想在我的视图模型中删除与视图相关的代码(具有依赖项对象和可视树帮助器的代码),因为这会以某种方式破坏可测试性.但另一方面,这种方式我避免当用户没有点击一行而是在标题上发生某些事情时.

PS:我试着看一下附加的行为,但是我无法在工作中从Skydrive下载,所以"内置"解决方案最好.

bli*_*eis 31

你为什么不简单地使用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>
Run Code Online (Sandbox Code Playgroud)

你的命令是这样的:

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

        return mouseDoubleClickCommand;
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:我现在用这个而不是Interaction.Triggers:

<DataGrid.InputBindings>
    <MouseBinding MouseAction="LeftDoubleClick"
                  Command="{Binding Path=MouseDoubleClickCommand}"
                  CommandParameter="{Binding ElementName=myGrd, Path=SelectedItem}" />
</DataGrid.InputBindings>
Run Code Online (Sandbox Code Playgroud)

  • 你节省了多少时间和精力,让'i'离开'myGrd'?:-) (6认同)
  • 如果你想阻止mousedoubleclick你可以尝试PreviewMouseDoubleClick并为你的条件设置e.Handled = true.所以你可以从viewmodel中重新编写代码并将其放在数据网格的代码隐藏中 (2认同)

Ric*_*d E 12

以下是使用附加行为实现它的方法:

编辑:现在上注册的行为DataGridRow,而不是DataGrid使DataGridHeader点击被忽略.

行为:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

然后,您需要修改您MouseDoubleClickCommand的删除MouseButtonEventArgs参数并将其替换为您的SelectedItem类型.


Mas*_*low 8

比这里提出的任何解决方案更简单.

我正在使用这个.

<!-- 
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>
Run Code Online (Sandbox Code Playgroud)

WPF DataGrid:CommandBinding到双击而不是使用事件