我已经尝试了这些建议,并且我在其他网站上找到了很多其他建议,但没有一个对我很有效。最后,我创建了以下解决方案。
我创建了自己的 DataGrid 继承控件,并简单地将以下代码添加到其中:
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;
}
}
这一切有什么作用?
好吧,每次我们单击 DataGrid 中的任何单元格时,我们都会查看该单元格中是否包含 CheckBox 控件。如果它确实,那么我们会将焦点设置到该复选框并切换它的值。
这似乎对我有用,并且是一个很好的、易于重复使用的解决方案。
令人失望的是,我们需要编写代码来做到这一点。第一次鼠标单击(在 DataGrid 的 CheckBox 上)被“忽略”,因为 WPF 使用它将行置于编辑模式中的解释听起来合乎逻辑,但在现实世界中,这与每个实际应用程序的工作方式背道而驰。
如果用户在他们的屏幕上看到一个复选框,他们应该能够单击它一次以勾选/取消勾选它。故事结束。