WPF为DataGridTextColumn添加PreviewMouseDown事件实现点击弹出自定义键盘
WPF DataGrid单元格点击弹出自定义键盘实现方案
DataGridTextColumn 不属于可视化树内的元素,无法直接挂载PreviewMouseDown事件,有两种可落地的实现路径,按需选择即可。
方法1:按列挂载事件(精准控制触发键盘的列范围)
针对需要触发键盘的列,分别给只读显示态的TextBlock、编辑态的TextBox挂载事件即可,基于你提供的代码修改如下:
第一步 修改XAML代码
<DataGrid x:Name="datagridusers" materialDesign:ColorZoneAssist.Background="Wheat" VerticalAlignment="Top" Height="400" Margin="20 80 20 20" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Style="{StaticResource MaterialDesignDataGrid}" FontSize="15" materialDesign:ScrollViewerAssist.SupportHorizontalScroll="True" CanUserAddRows="False" AutoGenerateColumns="False"> <DataGrid.Columns> <materialDesign:DataGridTextColumn Header="USER ID" Binding="{Binding Id}" IsReadOnly="True"> <DataGridTextColumn.ElementStyle> <Style TargetType="TextBlock"> <Setter Property="TextBlock.TextWrapping" Value="Wrap" /> <Setter Property="TextBlock.TextAlignment" Value="Center"/> <!-- 只读态文本块挂载鼠标预览事件 --> <EventSetter Event="PreviewMouseDown" Handler="DataGridCell_PreviewMouseDown"/> </Style> </DataGridTextColumn.ElementStyle> </materialDesign:DataGridTextColumn> <!-- 可编辑列示例,需要同时给显示态、编辑态控件挂载事件 --> <materialDesign:DataGridTextColumn Header="USER NAME" Binding="{Binding UserName}"> <DataGridTextColumn.ElementStyle> <Style TargetType="TextBlock"> <Setter Property="TextBlock.TextWrapping" Value="Wrap" /> <Setter Property="TextBlock.TextAlignment" Value="Center"/> <EventSetter Event="PreviewMouseDown" Handler="DataGridCell_PreviewMouseDown"/> </Style> </DataGridTextColumn.ElementStyle> <DataGridTextColumn.EditingElementStyle> <Style TargetType="TextBox"> <EventSetter Event="PreviewMouseDown" Handler="DataGridCell_PreviewMouseDown"/> </Style> </DataGridTextColumn.EditingElementStyle> </materialDesign:DataGridTextColumn> </DataGrid.Columns > </DataGrid>
注意:Style必须显式声明
TargetType,否则EventSetter无法匹配到对应控件的事件。
第二步 编写后台事件逻辑
// 记录当前激活的输入控件,用于自定义键盘回传输入内容 private UIElement _currentInputTarget; private void DataGridCell_PreviewMouseDown(object sender, MouseButtonEventArgs e) { _currentInputTarget = sender as UIElement; // 可编辑列自动进入编辑状态 DataGridCell clickedCell = FindVisualParent<DataGridCell>(sender as DependencyObject); if (clickedCell != null && !clickedCell.IsReadOnly && !clickedCell.IsEditing) { clickedCell.IsEditing = true; // 异步等待编辑控件加载完成后切换焦点 Dispatcher.BeginInvoke(new Action(() => { if (clickedCell.Content is TextBox editTb) { editTb.Focus(); _currentInputTarget = editTb; } }), System.Windows.Threading.DispatcherPriority.Input); } // 弹出自定义键盘逻辑,以下示例基于Popup承载键盘 if (KeyboardPopup != null) { // 定位键盘到当前单元格下方 Point popPos = _currentInputTarget.TranslatePoint(new Point(0, _currentInputTarget.RenderSize.Height), this); KeyboardPopup.PlacementRectangle = new Rect(popPos.X, popPos.Y, 0, 0); KeyboardPopup.IsOpen = true; } } // 可视化树查找辅助方法 private static T FindVisualParent<T>(DependencyObject child) where T : DependencyObject { DependencyObject parent = VisualTreeHelper.GetParent(child); if (parent == null) return null; return parent as T ?? FindVisualParent<T>(parent); }
方法2:全局挂载事件(适合列数多、所有可编辑单元格都要触发键盘的场景)
不用给每列单独加样式,直接给DataGrid本身挂载PreviewMouseDown事件,在事件里过滤点击源即可:
XAML修改
直接在DataGrid标签上追加事件配置,其余属性保持不变:
<DataGrid x:Name="datagridusers" PreviewMouseDown="Datagridusers_PreviewMouseDown">
后台逻辑
private void Datagridusers_PreviewMouseDown(object sender, MouseButtonEventArgs e) { // 只响应单元格内文本块、输入框的点击 if (e.OriginalSource is not TextBlock and not TextBox) return; _currentInputTarget = e.OriginalSource as UIElement; // 后续进入编辑状态、弹键盘的逻辑和方法1完全一致 }
自定义键盘适配注意点
- 自定义键盘的所有控件要设置
Focusable="False",避免点击键盘按钮抢走单元格的输入焦点,导致内容无法正常写入 - 点击键盘按键时,如果当前目标是
TextBox,直接操作SelectedText属性插入/删除内容即可;如果是只读列的TextBlock,直接修改其绑定的数据源对应属性,WPF绑定机制会自动刷新UI - 点击DataGrid其他区域、窗口其他区域时记得关闭键盘Popup,避免遮挡界面
内容的提问来源于stack exchange,提问作者Mustafa Şan
相关产品推荐
相关产品推荐

