Ich habe diese Vorschläge ausprobiert und viele andere, die ich auf anderen Websites gefunden habe, aber keiner von ihnen hat für mich ganz funktioniert. Am Ende habe ich die folgende Lösung erstellt.
Ich habe mein eigenes DataGrid-geerbtes Steuerelement erstellt und einfach diesen Code hinzugefügt:
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;
}
}
Was macht das alles?
Nun, jedes Mal, wenn wir auf eine Zelle in unserem DataGrid klicken, sehen wir, ob die Zelle ein CheckBox-Steuerelement enthält. Wenn dies der Fall ist , setzen wir den Fokus auf diese CheckBox und schalten ihren Wert um .
Dies scheint für mich zu funktionieren und ist eine schöne, leicht wiederverwendbare Lösung.
Es ist enttäuschend , dass wir brauchen , um Code schreiben dies aber zu tun. Die Erklärung, dass der erste Mausklick (auf das Kontrollkästchen eines DataGrid) "ignoriert" wird, da WPF die Zeile damit in den Bearbeitungsmodus versetzt, mag logisch klingen, aber in der realen Welt widerspricht dies der Funktionsweise jeder realen Anwendung.
Wenn ein Benutzer ein Kontrollkästchen auf seinem Bildschirm sieht, sollte er einmal darauf klicken können, um es anzukreuzen / zu deaktivieren. Ende der Geschichte.