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。
我正在尝试设置一个数据网格,以便当网格获得焦点时,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。