You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF中如何为DataGrid动态生成的文本框编辑单元格添加上下文菜单?

解决方案:给自动生成列的DataGrid编辑文本框添加自定义上下文菜单

因为你的DataGrid是自动生成列的,没办法直接在XAML里定义编辑控件的上下文菜单,所以我们得通过AutoGeneratingColumn事件来为每个文本列的编辑TextBox添加自定义菜单,具体步骤如下:

1. 在XAML中添加资源和事件绑定

首先,在Window/UserControl的资源里定义你的上下文菜单,同时给DataGrid绑定AutoGeneratingColumn事件:

<Window.Resources>
    <!-- 自定义上下文菜单 -->
    <ContextMenu x:Key="TextBoxEditContextMenu">
        <MenuItem Header="Contains..." Click="ContainsMenuItem_Click"/>
        <MenuItem Header="Does not contain..." Click="DoesNotContainMenuItem_Click"/>
    </ContextMenu>
</Window.Resources>

<DataGrid x:Name="dataGrid" 
          Margin="10,35,10,40"
          AutoGeneratingColumn="DataGrid_AutoGeneratingColumn"/>

2. 处理AutoGeneratingColumn事件,为文本列绑定编辑样式

在后台代码里,捕获自动生成的文本列,给它的编辑元素(TextBox)设置带上下文菜单的样式:

private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    // 只处理文本类型的列
    if (e.Column is DataGridTextColumn textColumn)
    {
        // 创建TextBox的编辑样式
        var editingStyle = new Style(typeof(TextBox));
        
        // 从资源中取出上下文菜单,绑定到TextBox
        var contextMenu = (ContextMenu)FindResource("TextBoxEditContextMenu");
        editingStyle.Setters.Add(new Setter(TextBox.ContextMenuProperty, contextMenu));
        
        // 可选:添加选中文本的事件,控制菜单是否可用
        editingStyle.Setters.Add(new EventSetter(TextBox.SelectionChangedEvent, new RoutedEventHandler(TextBox_SelectionChanged)));
        
        // 将样式应用到文本列的编辑元素上
        textColumn.EditingElementStyle = editingStyle;
    }
}

3. 控制菜单可用性(可选)

如果你希望只有当文本框中有选中内容时,菜单选项才可用,可以处理TextBox的SelectionChanged事件:

private void TextBox_SelectionChanged(object sender, RoutedEventArgs e)
{
    if (sender is TextBox textBox)
    {
        var contextMenu = textBox.ContextMenu;
        if (contextMenu == null) return;
        
        // 根据是否有选中文本,切换菜单选项的启用状态
        bool hasSelectedText = !string.IsNullOrEmpty(textBox.SelectedText);
        foreach (var item in contextMenu.Items.OfType<MenuItem>())
        {
            item.IsEnabled = hasSelectedText;
        }
    }
}

4. 实现菜单点击后的筛选操作

接下来处理菜单的点击事件,这里以筛选DataGrid数据为例(根据选中的文本进行包含/不包含筛选):

// 辅助方法:转义LIKE语句中的特殊字符,避免筛选出错
private string EscapeLikeFilterText(string input)
{
    // 处理单引号、%、_这些SQL LIKE的特殊字符
    return input.Replace("'", "''")
                .Replace("%", "[%]")
                .Replace("_", "[_]");
}

private void ContainsMenuItem_Click(object sender, RoutedEventArgs e)
{
    if (sender is MenuItem menuItem && menuItem.DataContext is TextBox textBox)
    {
        string selectedText = textBox.SelectedText;
        if (string.IsNullOrEmpty(selectedText)) return;
        
        // 获取当前编辑列的属性名,用于筛选
        var dataGridColumn = dataGrid.Columns.First(col => 
            col.GetCellContent(textBox.DataContext) is TextBlock && 
            col.SortMemberPath == ((Binding)textBox.GetBindingExpression(TextBox.TextProperty).ParentBinding).Path.Path);
        string columnName = ((PropertyDescriptor)dataGridColumn.SortMemberPath).Name;
        
        // 给DataView设置筛选条件
        string escapedText = EscapeLikeFilterText(selectedText);
        LogFileItemDataTable.DefaultView.RowFilter = $"[{columnName}] LIKE '%{escapedText}%'";
    }
}

private void DoesNotContainMenuItem_Click(object sender, RoutedEventArgs e)
{
    if (sender is MenuItem menuItem && menuItem.DataContext is TextBox textBox)
    {
        string selectedText = textBox.SelectedText;
        if (string.IsNullOrEmpty(selectedText)) return;
        
        var dataGridColumn = dataGrid.Columns.First(col => 
            col.GetCellContent(textBox.DataContext) is TextBlock && 
            col.SortMemberPath == ((Binding)textBox.GetBindingExpression(TextBox.TextProperty).ParentBinding).Path.Path);
        string columnName = ((PropertyDescriptor)dataGridColumn.SortMemberPath).Name;
        
        string escapedText = EscapeLikeFilterText(selectedText);
        LogFileItemDataTable.DefaultView.RowFilter = $"[{columnName}] NOT LIKE '%{escapedText}%'";
    }
}

关键说明

  • 因为DataGrid是自动生成列,必须通过AutoGeneratingColumn事件才能访问到每一列,这样才能给动态生成的文本列编辑控件添加上下文菜单。
  • 用DataView.RowFilter筛选数据是最适合你DataTable数据源场景的方式,简单直接。
  • 转义特殊字符是为了避免筛选语句出错,比如文本里包含单引号时会导致语法错误。

内容的提问来源于stack exchange,提问作者Derek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:31:27