Eu tentei essas sugestões e muitas outras que encontrei em outros sites, mas nenhuma delas funcionou para mim. No final, criei a seguinte solução.
Eu criei meu próprio controle herdado do DataGrid e simplesmente adicionei esse código a ele:
public class DataGridWithNavigation : Microsoft.Windows.Controls.DataGrid
{
public DataGridWithNavigation()
{
EventManager.RegisterClassHandler(typeof(DataGridCell),
DataGridCell.PreviewMouseLeftButtonDownEvent,
new RoutedEventHandler(this.OnPreviewMouseLeftButtonDown));
}
private void OnPreviewMouseLeftButtonDown(object sender, RoutedEventArgs e)
{
DataGridCell cell = sender as DataGridCell;
if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
{
DependencyObject obj = FindFirstControlInChildren(cell, "CheckBox");
if (obj != null)
{
System.Windows.Controls.CheckBox cb = (System.Windows.Controls.CheckBox)obj;
cb.Focus();
cb.IsChecked = !cb.IsChecked;
}
}
}
public DependencyObject FindFirstControlInChildren(DependencyObject obj, string controlType)
{
if (obj == null)
return null;
// Get a list of all occurrences of a particular type of control (eg "CheckBox")
IEnumerable<DependencyObject> ctrls = FindInVisualTreeDown(obj, controlType);
if (ctrls.Count() == 0)
return null;
return ctrls.First();
}
public IEnumerable<DependencyObject> FindInVisualTreeDown(DependencyObject obj, string type)
{
if (obj != null)
{
if (obj.GetType().ToString().EndsWith(type))
{
yield return obj;
}
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
foreach (var child in FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type))
{
if (child != null)
{
yield return child;
}
}
}
}
yield break;
}
}
O que tudo isso faz?
Bem, cada vez que clicamos em qualquer célula do nosso DataGrid, vemos se a célula contém um controle CheckBox dentro dela. Se isso acontecer , definiremos o foco para essa caixa de seleção e alternaremos seu valor .
Isso parece funcionar para mim e é uma solução agradável e facilmente reutilizável.
É decepcionante que precisamos escrever código para fazer isso. A explicação de que o primeiro clique do mouse (na caixa de seleção de um DataGrid) é "ignorada", pois o WPF a utiliza para colocar a linha no modo de edição pode parecer lógica, mas no mundo real, isso contraria o modo como todos os aplicativos reais funcionam.
Se um usuário vir uma caixa de seleção na tela, ele poderá clicar nela uma vez para marcar / desmarcar. Fim da história.