我终于找到了这个问题的最佳解答,我已经苦苦思索了很长时间。
在某个时刻,我确认在DataGrid中按下Ctrl+Tab会得到期望的行为。
基于此,我认为我可以在DataGrid中交换KeyboardNavigation.TabNavigation附加属性和KeyboardNavigation.ControlTabNavigation附加属性的值。
然而,它并没有起作用。
在使用ReferenceSource检查DataGrid的子元素代码后,我进一步认为我应该在DataGridCellsPanel中交换KeyboardNavigation.TabNavigation附加属性和KeyboardNavigation.ControlTabNavigation附加属性的值。
我运行了它,并得到了理想的行为。
更重要的是,当焦点重新进入时,当前单元格仍然是失去焦点时的当前单元格。
<DataGrid KeyboardNavigation.TabNavigation="Once"
KeyboardNavigation.ControlTabNavigation="Continue">
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<DataGridCellsPanel KeyboardNavigation.TabNavigation="Continue"
KeyboardNavigation.ControlTabNavigation="Local"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.RowStyle>
</DataGrid>
它还可以通过以下附加属性实现,参考WinForms中DataGridView的StandardTab属性。
对于VB.net来说。
Public Class DataGridHelper
Public Shared Function GetStandardTab(element As DataGrid) As Boolean
If element Is Nothing Then Throw New ArgumentNullException(NameOf(element))
Return CBool(element.GetValue(StandardTabProperty))
End Function
Public Shared Sub SetStandardTab(element As DataGrid, value As Boolean)
If element Is Nothing Then Throw New ArgumentNullException(NameOf(element))
element.SetValue(StandardTabProperty, value)
End Sub
Public Shared ReadOnly StandardTabProperty As DependencyProperty =
DependencyProperty.RegisterAttached("StandardTab",
GetType(Boolean), GetType(DataGridHelper),
New FrameworkPropertyMetadata(False, FrameworkPropertyMetadataOptions.Inherits, New PropertyChangedCallback(AddressOf OnStandardTabPropertyChanged)))
Private Shared Sub OnStandardTabPropertyChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
If TypeOf d Is DataGrid OrElse TypeOf d Is DataGridCellsPanel Then
If CBool(e.NewValue) Then
If TypeOf d Is DataGridCellsPanel Then
d.SetValue(KeyboardNavigation.TabNavigationProperty, KeyboardNavigationMode.Continue)
d.SetValue(KeyboardNavigation.ControlTabNavigationProperty, KeyboardNavigationMode.Local)
Else
d.SetValue(KeyboardNavigation.TabNavigationProperty, KeyboardNavigationMode.Once)
d.SetValue(KeyboardNavigation.ControlTabNavigationProperty, KeyboardNavigationMode.Continue)
End If
Else
d.ClearValue(KeyboardNavigation.TabNavigationProperty)
d.ClearValue(KeyboardNavigation.ControlTabNavigationProperty)
End If
End If
End Sub
End Class
对于C#(未经测试)
public class DataGridHelper
{
public static bool GetStandardTab(DataGrid element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return (bool)element.GetValue(StandardTabProperty);
}
public static void SetStandardTab(DataGrid element, bool value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
element.SetValue(StandardTabProperty, value);
}
public static readonly DependencyProperty StandardTabProperty =
DependencyProperty.RegisterAttached("StandardTab",
typeof(bool), typeof(DataGridHelper),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(OnStandardTabPropertyChanged)));
private static void OnStandardTabPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is DataGrid || d is DataGridCellsPanel)
{
if ((bool) e.NewValue)
{
if (d is DataGridCellsPanel)
{
d.SetValue(KeyboardNavigation.TabNavigationProperty, KeyboardNavigationMode.Continue);
d.SetValue(KeyboardNavigation.ControlTabNavigationProperty, KeyboardNavigationMode.Local);
}
else
{
d.SetValue(KeyboardNavigation.TabNavigationProperty, KeyboardNavigationMode.Once);
d.SetValue(KeyboardNavigation.ControlTabNavigationProperty, KeyboardNavigationMode.Continue);
}
}
else
{
d.ClearValue(KeyboardNavigation.TabNavigationProperty);
d.ClearValue(KeyboardNavigation.ControlTabNavigationProperty);
}
}
}
}
FocusManager.SetFocusedElement
会导致两个问题:1. 它会将 '\t' 重新提交为所选单元格的输入;2. 它偶尔会无法设置键盘焦点和/或选择下一个单元格。使用Dispatcher.BeginInvoke(new Action(() => cell.Focus()));
应该可以解决这两个问题。 - wondra