IsReadOnlyProperty.OverrideMetadata 中断 WPF DataGrid 子类中的鼠标双击命令

问题描述 投票:0回答:1

我有一个 DataGrid 的子类,它提供了一些额外的功能并修改了它的一些属性的默认值。特别的一件事是我希望网格默认是只读的,所以我在它的构造函数中设置了

IsReadOnly = true

最近,我遇到了一个问题,即在模板中使用网格导致它是只读的,无论在模板中如何设置

IsReadOnly
。查看 dependency property precedence 页面,我得出的结论是 overriding metadata for
IsReadOnlyProperty
是更改其默认值的正确方法:

IsReadOnlyProperty.OverrideMetadata(typeof(NewDataGrid), new FrameworkPropertyMetadata(true));

虽然这解决了控件模板的问题,但它似乎破坏了鼠标双击命令绑定:

<DataGrid.InputBindings>
    <MouseBinding Gesture="LeftDoubleClick" Command="{StaticResource DoubleClickCommand}"/>
</DataGrid.InputBindings>

有没有更好的方法来更改

IsReadOnly
的默认值而不破坏鼠标绑定和/或模板?

wpf datagrid double-click
1个回答
0
投票

我怀疑您的问题与覆盖

DataGrid.IsReadOnly
属性的默认值有关。只读
DataGrid
和鼠标输入事件之间没有逻辑关系。

相反,鼠标事件看起来是由

DataGrid
的内部元素处理的,例如
DataGridCell
。例如,双击
DataGrid
的背景将按预期工作。

要修复它,我建议重写控件的

Control.OnMouseDoubleClick
和/或
Control.OnPreviewMouseDoubleClick
方法。
这通常应该是您在注册事件处理程序之前的第一种方法。首先覆盖自定义或扩展控件的虚拟成员。它会给你更大的控制权,你的代码看起来也更干净。
这是因为即使覆盖是虚拟事件调用器(例如
Control.OnPreviewMouseDoubleClick
)并且控件决定不引发公共关联事件,覆盖总是被调用。

因此,不要注册鼠标手势,而是覆盖继承的事件调用器:

public class NewDataGrid : DataGrid
{
  static NewDataGrid() 
    => DataGrid.IsReadOnlyProperty.OverrideMetadata(typeof(MyDataGrid), new FrameworkPropertyMetadata(true));

  protected override void OnMouseDoubleClick(MouseButtonEventArgs e) 
  {
    base.OnMouseDoubleClick(e);

    if (e.LeftButton is MouseButtonState.Pressed)
    {
      // TODO::Handle left double click mouse input
    }
  }

  protected override void OnPreviewMouseDoubleClick(MouseButtonEventArgs e)
  {
    base.OnPreviewMouseDoubleClick(e);

    if (e.LeftButton is MouseButtonState.Pressed)
    {
      // TODO::Handle left double click preview mouse input
    }
  }
}

这与推荐的修复程序无关,而是关于您的原始实施的一般建议:您使用

MouseBinding.Command
标记扩展设置
StaticResource
的方式看起来很奇怪。该命令应该是
RoutedCommand
,通常定义为
static
并在 XAML 中使用
x:Static
扩展名引用:

public class NewDataGrid : DataGrid
{
  public static RoutedCommand DoubleClickCommand { get; } = new RoutedUICommand(
    "Raise the tunneling and bubbling MouseDoubleClick event", 
    "DoubleClickCommand", 
    typeof(NewDataGrid));

  public NewDataGrid() 
  {
    var doubleClickCommandBinding = new CommandBinding(DoubleClickCommand, ExecuteDoubleClickCommand, CanExecuteDoubleClickCommand);
    this.CommandBindings.Add(doubleClickCommandBinding); 
  }

  private void CanExecuteDoubleClickCommand(object sender, CanExecuteRoutedEventArgs e) 
    => e.CanExecute = true;

  private void ExecuteDoubleClickCommand(object sender, ExecutedRoutedEventArgs e) 
  {
    var eventArgs = new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Left);
    OnPreviewMouseDoubleClick(eventArgs);
    OnMouseDoubleClick(eventArgs); 
  }
}
<NewDataGrid.InputBindings>
    <MouseBinding Gesture="LeftDoubleClick" 
                  Command="{x:Static local:NewDataGrid.DoubleClickCommand}" />
</NewDataGrid.InputBindings>
© www.soinside.com 2019 - 2024. All rights reserved.