You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为WPF DataGrid每行添加带参数的MouseDoubleClick命令触发?

问题

我在XAML中有一个DataGrid,想要给每个DataGridRow添加MouseDoubleClick事件,调用带参数的命令。但遇到两个限制:

  • 无法用EventSetter绑定命令(因为需要传递参数);
  • 不能用代码后置:一是用了ViewModel定位器,强转DataContext不够优雅;二是目标方法是异步方法,而事件Handler要求返回void而非Task。

原XAML代码

<DataGrid
     AutoGenerateColumns="False"
     Grid.Row="2"
     IsReadOnly="True"
     ItemsSource="{Binding Entities, Converter={x:Static convertors:FileEntityEnumerableToFileDataGridEntityEnumerableConvertor.Instance}}"
     Name="ViewerDataGrid"
     SelectedItem="{Binding SelectedItem}"
     Visibility="{Binding IsDataGridVisible, Converter={x:Static materialDesign:BooleanToVisibilityConverter.HiddenInstance}}">
     <DataGrid.Resources>
          <Style BasedOn="{StaticResource MaterialDesignDataGridColumnHeader}" TargetType="DataGridColumnHeader">
              <Setter Property="Background" Value="{Binding ElementName=CloseButton, Path=Background}" />
          </Style>

          <Style BasedOn="{StaticResource MaterialDesignDataGridCell}" TargetType="DataGridCell">
              <Style.Triggers>
                  <Trigger Property="IsSelected" Value="True">
                      <Setter Property="BorderBrush" Value="Transparent" />
                  </Trigger>
              </Style.Triggers>
          </Style>
     </DataGrid.Resources>
     <DataGrid.Columns>
         <DataGridTextColumn Binding="{Binding Name}" Header="Name" />
         <DataGridTextColumn Binding="{Binding Size}" Header="Size" />
         <DataGridTextColumn Binding="{Binding LastChanging}" Header="Last changing" />
         <DataGridTextColumn Binding="{Binding CreatedAt}" Header="Created at" />
     </DataGrid.Columns>
     <DataGrid.RowStyle>
         <Style BasedOn="{StaticResource {x:Type DataGridRow}}" TargetType="{x:Type DataGridRow}">
             <Setter Property="i:Interaction.Triggers">
                 <Setter.Value>
                     <i:Interaction.Triggers>
                         <i:EventTrigger EventName="MouseDoubleClick">
                             <i:InvokeCommandAction Command="{Binding DataContext.ResetDirectoryContentCommand, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" CommandParameter="{Binding}" />
                         </i:EventTrigger>
                     </i:Interaction.Triggers>
                 </Setter.Value>
             </Setter>
         </Style>
     </DataGrid.RowStyle>
</DataGrid>

尝试过的无效方式

<DataGrid.RowStyle>
     <Style BasedOn="{StaticResource {x:Type DataGridRow}}" TargetType="{x:Type DataGridRow}">
         <EventSetter Event="MouseDoubleClick" Handler="{Binding DataContext.ResetDirectoryContentCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
     </Style>
</DataGrid.RowStyle>

解决方案

方案1:使用Microsoft.Xaml.Behaviors(Blend交互行为)

你原XAML中的写法方向是对的,只需补充异步命令的实现即可:

  1. 引入NuGet包:安装Microsoft.Xaml.Behaviors.Wpf(WPF项目),确保XAML头部已声明命名空间:
    xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
    
  2. 实现异步命令:封装支持异步逻辑的ICommand,避免UI阻塞并处理重复点击:
    public class AsyncRelayCommand<T> : ICommand
    {
        private readonly Func<T, Task> _execute;
        private readonly Predicate<T> _canExecute;
        private bool _isExecuting;
    
        public event EventHandler CanExecuteChanged;
    
        public AsyncRelayCommand(Func<T, Task> execute, Predicate<T> canExecute = null)
        {
            _execute = execute ?? throw new ArgumentNullException(nameof(execute));
            _canExecute = canExecute;
        }
    
        public bool CanExecute(object parameter)
        {
            return !_isExecuting && (_canExecute?.Invoke((T)parameter) ?? true);
        }
    
        public async void Execute(object parameter)
        {
            if (!CanExecute(parameter)) return;
            _isExecuting = true;
            try
            {
                await _execute((T)parameter);
            }
            finally
            {
                _isExecuting = false;
                RaiseCanExecuteChanged();
            }
        }
    
        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged?.Invoke(this, EventArgs.Empty);
        }
    }
    
  3. ViewModel中定义命令:
    public AsyncRelayCommand<YourEntityType> ResetDirectoryContentCommand { get; }
    
    public YourViewModel()
    {
        ResetDirectoryContentCommand = new AsyncRelayCommand<YourEntityType>(ExecuteResetDirectoryContent);
    }
    
    private async Task ExecuteResetDirectoryContent(YourEntityType entity)
    {
        // 你的异步业务逻辑
    }
    
  4. 保留原XAML的RowStyle:你的写法已经正确绑定了命令和当前行的实体参数,只要命令是异步实现即可正常工作。

方案2:自定义附加属性(无额外依赖)

如果不想引入第三方包,可以自己写附加属性处理事件绑定:

  1. 实现附加属性类:
    public static class DataGridRowExtensions
    {
        public static readonly DependencyProperty DoubleClickCommandProperty =
            DependencyProperty.RegisterAttached(
                "DoubleClickCommand",
                typeof(ICommand),
                typeof(DataGridRowExtensions),
                new PropertyMetadata(null, OnDoubleClickCommandChanged));
    
        public static ICommand GetDoubleClickCommand(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(DoubleClickCommandProperty);
        }
    
        public static void SetDoubleClickCommand(DependencyObject obj, ICommand value)
        {
            obj.SetValue(DoubleClickCommandProperty, value);
        }
    
        private static void OnDoubleClickCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is DataGridRow row)
            {
                row.MouseDoubleClick -= Row_MouseDoubleClick;
                if (e.NewValue is ICommand command)
                {
                    row.MouseDoubleClick += Row_MouseDoubleClick;
                }
            }
        }
    
        private static async void Row_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (sender is DataGridRow row && GetDoubleClickCommand(row) is AsyncRelayCommand<object> asyncCommand)
            {
                await ((Func<object, Task>)asyncCommand.Execute).Invoke(row.DataContext);
            }
            else if (sender is DataGridRow row && GetDoubleClickCommand(row) is ICommand syncCommand)
            {
                syncCommand.Execute(row.DataContext);
            }
        }
    }
    
  2. XAML中使用附加属性:
    先引入自定义类的命名空间(假设命名空间为YourNamespace):
    xmlns:local="clr-namespace:YourNamespace"
    
    再修改RowStyle:
    <DataGrid.RowStyle>
        <Style BasedOn="{StaticResource {x:Type DataGridRow}}" TargetType="{x:Type DataGridRow}">
            <Setter Property="local:DataGridRowExtensions.DoubleClickCommand" 
                    Value="{Binding DataContext.ResetDirectoryContentCommand, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
        </Style>
    </DataGrid.RowStyle>
    

内容的提问来源于stack exchange,提问作者TheMakarik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 15:54:52