WPF DataGrid:如何单击(或触摸)选中DataGridCell内的控件
解决WPF DataGridTemplateColumn单击直接进入TextBox编辑状态的问题
你的思路方向是对的,但核心问题在于设置IsEditing = true后,CellEditingTemplate中的TextBox还未完成加载,此时直接查找控件会失败,导致需要二次点击才能获取焦点。以下是两种可行的解决方案:
方案一:利用TextBox的Loaded事件自动获取焦点
直接在CellEditingTemplate的TextBox上添加Loaded事件,控件加载完成后自动获取焦点:
修改XAML代码
<DataGridTemplateColumn Header="Comment" Width="Auto"> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <Grid> <TextBox Name="InputTextBox" Text="{st:WpfBinding Path=Comment}" Loaded="InputTextBox_Loaded" /> </Grid> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Grid> <TextBlock Text="{Binding Path=Comment}" PreviewMouseDown="UIElement_OnPreviewMouseDown" /> </Grid> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
后台事件处理
private void InputTextBox_Loaded(object sender, RoutedEventArgs e) { if (sender is TextBox textBox) { textBox.Focus(); // 可选:将光标定位到文本末尾,提升编辑体验 textBox.Select(textBox.Text.Length, 0); } } private void UIElement_OnPreviewMouseDown(object sender, MouseButtonEventArgs e) { var targetCell = GetDataGridCell(sender, e); if (targetCell != null) { targetCell.IsEditing = true; e.Handled = true; // 阻止默认事件,避免DataGrid的后续处理干扰 } } private DataGridCell GetDataGridCell(object sender, MouseEventArgs e) { var hit = VisualTreeHelper.HitTest((Visual)sender, e.GetPosition((IInputElement)sender)); DependencyObject cell = VisualTreeHelper.GetParent(hit.VisualHit); while (cell != null && !(cell is DataGridCell)) { cell = VisualTreeHelper.GetParent(cell); } return cell as DataGridCell; }
方案二:通过Dispatcher延迟查找TextBox
在设置IsEditing = true后,利用Dispatcher以Render优先级延迟执行查找操作,确保CellEditingTemplate已加载完成:
修改后台事件处理代码
private void UIElement_OnPreviewMouseDown(object sender, MouseButtonEventArgs e) { var targetCell = GetDataGridCell(sender, e); if (targetCell != null) { targetCell.IsEditing = true; // 延迟执行,等待CellEditingTemplate加载 Dispatcher.BeginInvoke(new Action(() => { var textBox = FindVisualChild<TextBox>(targetCell); if (textBox != null) { textBox.Focus(); textBox.Select(textBox.Text.Length, 0); } }), System.Windows.Threading.DispatcherPriority.Render); e.Handled = true; } } // 通用可视化树子控件查找方法 private T FindVisualChild<T>(DependencyObject parent) where T : DependencyObject { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) { var child = VisualTreeHelper.GetChild(parent, i); if (child is T typedChild) return typedChild; var result = FindVisualChild<T>(child); if (result != null) return result; } return null; } // 保留你原有的GetDataGridCell方法 private DataGridCell GetDataGridCell(object sender, MouseEventArgs e) { var hit = VisualTreeHelper.HitTest((Visual)sender, e.GetPosition((IInputElement)sender)); DependencyObject cell = VisualTreeHelper.GetParent(hit.VisualHit); while (cell != null && !(cell is DataGridCell)) { cell = VisualTreeHelper.GetParent(cell); } return cell as DataGridCell; }
关键注意事项
- 确保DataGrid的
IsReadOnly属性为false,同时目标列的IsReadOnly也需设为false(默认就是false,若手动修改过需检查)。 - 设置
e.Handled = true是必要的,否则DataGrid的默认鼠标事件处理会干扰焦点设置逻辑。
内容的提问来源于stack exchange,提问作者Nico
相关产品推荐
相关产品推荐

