WPF - 如何在不单击鼠标的情况下正确触发 DataGrid 中的编辑模式

WPF - How to correctly trigger edit mode in a DataGrid without a mouse click

我正在尝试设置一个数据网格,以便当网格获得焦点时,current/selected 行进入指定单元格的编辑模式。不幸的是,该行仍然需要单击鼠标才能使单元格进入编辑模式。

网格通过绑定到布尔值的 datatrigger 获得焦点,这正确地触发了后面代码中的 GotFocus 方法,该方法应该指定当前单元格和 BeginEdit。

XML代码:

<DataGrid x:Name="SampleAliquotsDataGrid" ItemsSource="{Binding Source={StaticResource cvsSampleModels}}" 
                  CurrentItem="{Binding CurrentSampleAliquot, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"                   
                  SelectedItem="{Binding CurrentSampleAliquot, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" 
                  AutoGenerateColumns="False" Grid.Row="1" SelectionUnit="FullRow"
                  GotFocus="SampleAliquotsDataGrid_GotFocus"
                  >
            <DataGrid.Style>
                <Style>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding DataGridHasFocus}" Value="True">
                            <Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=SampleAliquotsDataGrid}"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </DataGrid.Style>
            <DataGrid.Columns>
                <DataGridTemplateColumn Header="RecordID" Width="Auto" IsReadOnly="True">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Label Content="{Binding DBRecordID}" HorizontalContentAlignment="Right"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn x:Name="MeasuredResult" Binding="{Binding MeasuredResult, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="MeasuredResult" 
                                        FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"/>
               </DataGrid.Columns>                 
</DataGrid>

要编辑的单元格是 DataGridTextColumn“MeasuredResult”。

后面的gotfocus代码:

private void SampleAliquotsDataGrid_GotFocus(object sender, RoutedEventArgs e)
        {
            DataGrid grid = sender as DataGrid;
            
            grid.CurrentCell = new DataGridCellInfo(grid.SelectedItem, grid.Columns[1]);
            
            grid.BeginEdit();
            e.Handled = true;
        }

我试过更改当前单元格的设置方式,在调用 BeginEdit 之前重新关注网格,将选择单位更改为单元格而不是整行。

希望解决方案不会太复杂,我的 WPF 技能并不高明。

我建议以下行为:

  • 单击 selected 行上的单元格时,DataGrid 的行为没有改变。
  • 当在非 select 行上单击单元格时,它的行被 selected 并且 AutoEditColumn 中的单元格被设置为编辑模式。
  • DataGrid 从键盘(选项卡导航)获得焦点时,AutoEditColumn 和 select 行中的单元格设置为编辑模式。

要实现这一点,可以监听 CurrentCellChanged 事件。
这里有一个助手 class 实现了所描述的行为:

private class AutoEditColumnHelper : IDisposable
{
    private readonly DataGrid _dataGrid;
    private readonly int _columnIndex;

    private object? _lastItem;

    public AutoEditColumnHelper(DataGrid dataGrid, int columnIndex)
    {
        _dataGrid = dataGrid;
        _columnIndex = columnIndex;

        _dataGrid.CurrentCellChanged += OnCurrentCellChanged;
    }

    public void Dispose()
    {
        _dataGrid.CurrentCellChanged -= OnCurrentCellChanged;
    }

    private void OnCurrentCellChanged(object? sender, EventArgs e)
    {
        var currentCell = _dataGrid.CurrentCell;

        if (!currentCell.IsValid || Equals(currentCell.Item, _lastItem))
            return;

        var autoEditColumn = GetAutoEditColumn();
        if (autoEditColumn is null)
            return;

        _dataGrid.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, () =>
        {
            _lastItem = _dataGrid.SelectedItem;
            _dataGrid.CurrentCell = new DataGridCellInfo(_lastItem, autoEditColumn);
            _dataGrid.BeginEdit();
        });
    }

    private DataGridColumn? GetAutoEditColumn()
    {
        return _columnIndex < 0 || _columnIndex > _dataGrid.Columns.Count ? null : _dataGrid.Columns[_columnIndex];
    }
}

要使用此 class,AttachedProperty 是推荐的方式。

首先,我们声明一个 public AutoEditColumn 附加 属性 存储 AutoEditColumn 索引在 int.
然后,我们声明一个私有的 AutoEditColumnHelper attached 属性 为每个 DataGrid AutoEditColumn 属性 存储下面 AutoEditColumnHelper 的实例。

public static readonly DependencyProperty AutoEditColumnProperty = DependencyProperty.RegisterAttached("AutoEditColumn", typeof(int), typeof(DataGridEx), new PropertyMetadata(default(int), AutoEditColumnChangedCallback));

public static void SetAutoEditColumn(DependencyObject element, int value)
{
    element.SetValue(AutoEditColumnProperty, value);
}

public static int GetAutoEditColumn(DependencyObject element)
{
    return (int)element.GetValue(AutoEditColumnProperty);
}

private static void AutoEditColumnChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (d is not DataGrid dataGrid)
        return;

    GetAutoEditColumnHelper(dataGrid)?.Dispose();

    if (e.NewValue is int columnIndex)
    {
        SetAutoEditColumnHelper(d, new AutoEditColumnHelper(dataGrid, columnIndex));
    }
    else
    {
        d.ClearValue(AutoEditColumnHelperProperty);
    }
}


private static readonly DependencyProperty AutoEditColumnHelperProperty = DependencyProperty.RegisterAttached("AutoEditColumnHelper", typeof(AutoEditColumnHelper), typeof(DataGridEx), new PropertyMetadata(default(AutoEditColumnHelper)));

private static void SetAutoEditColumnHelper(DependencyObject element, AutoEditColumnHelper value)
{
    element.SetValue(AutoEditColumnHelperProperty, value);
}

private static AutoEditColumnHelper? GetAutoEditColumnHelper(DependencyObject element)
{
    return element.GetValue(AutoEditColumnHelperProperty) as AutoEditColumnHelper;
}

最后AutoEditColumn附属性用于xaml代码:

<DataGrid AutoGenerateColumns="False"
          so71475662:DataGridEx.AutoEditColumn="1"
          ItemsSource="{Binding Path=Items}"
          SelectionMode="Single"
          SelectionUnit="FullRow">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Label}" Header="Label" />
        <DataGridTextColumn Binding="{Binding Value}" Header="Value" />
    </DataGrid.Columns>
</DataGrid>

完整的工作示例可用 here