He intentado estas sugerencias y muchas otras que he encontrado en otros sitios, pero ninguna de ellas me funcionó. Al final, creé la siguiente solución.
Creé mi propio control heredado de DataGrid y simplemente le agregué este código:
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;
}
}
¿Qué hace todo esto?
Bueno, cada vez que hacemos clic en cualquier celda de nuestro DataGrid, vemos si la celda contiene un control CheckBox dentro de ella. Si lo hace , a continuación, vamos a establecer el foco a esa CheckBox y alternar su valor .
Esto parece funcionar para mí, y es una buena solución, fácilmente reutilizable.
Sin embargo, es decepcionante que necesitemos escribir código para hacer esto. La explicación de que el primer clic del mouse (en un CheckBox de DataGrid) se "ignora" a medida que WPF lo usa para poner la fila en modo Edición puede sonar lógico, pero en el mundo real, esto va en contra de la forma en que funciona cada aplicación real.
Si un usuario ve una casilla de verificación en su pantalla, debería poder hacer clic en ella una vez para marcarla o desmarcarla. Fin de la historia.