WPF - 数据网格上的上下文菜单

本文关键字:上下文 菜单 网格 数据 数据网 WPF | 更新日期: 2023-09-27 17:57:07

我的DataGrid绑定到数据源,即数据库。当用户右键单击DataGrid控件上的某处时,我希望能够识别他或她在哪一列上执行此操作。场景如下 - 如果在保存日期的列上打开ContextMenu,那么(例如)我想向他提供选项来过滤掉更小、更大或等于所选日期的日期。

<DataGrid.Resources>
        <Helpers:BindingProxy x:Key="proxy" Data="{Binding}" />
</DataGrid.Resources>
<DataGrid.ContextMenu>
        <ContextMenu DataContext="{Binding Path=DataContext}">
            <MenuItem Header="Cokolwiek" Command="{Binding Source={StaticResource proxy}, Path=Data.FK}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent.PlacementTarget.DataContext}"/>
        </ContextMenu>
</DataGrid.ContextMenu>

PlacementTarget是对DataGrid的引用,我希望它是对DataGridColumn的引用。

绑定代理类:

public class BindingProxy : Freezable {
    protected override Freezable CreateInstanceCore() {
        return new BindingProxy();
    }
    public object Data {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }
    // Using a DependencyProperty as the backing store for Data.
    // This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object),
        typeof(BindingProxy), new UIPropertyMetadata(null));
}

WPF - 数据网格上的上下文菜单

您可以做的是挂接到PreviewMouseUp事件,以便查看引发的EventSource属性。

除直接事件外,WPF 成对定义大多数路由事件 - 一个隧道事件和另一个冒泡事件。隧道事件名称始终以"预览"开头,并首先引发。这使父母有机会在事件到达孩子之前看到事件。其次是冒泡的对应物。在大多数情况下,您只会处理冒泡的。预览通常用于

阻止事件(e.Handle = true)导致父级在 升级到正常事件处理。

例如,如果 UI 树 = 按钮包含网格包含画布包含椭圆单击椭圆将导致(鼠标向下按钮被按钮吃掉,而是单击被抬起。

private void OnPreviewMouseUp(object sender, MouseButtonEventArgs mouseButtonEventArgs)
    {
        var source = mouseButtonEventArgs.Source;
        // Assuming the DataGridColumn's Template is just a TextBlock
        // but depending on the Template which for sure should at least inherit from FrameworkElement to have the Parent property.
        var textBlock = source as TextBlock;
        // Not a good check to know if it is a holding dates but it should give you the idea on what to do
        if (textBlock != null)
        {
            var dataGridColumn = textBlock.Parent as DataGridColumn;
            if (dataGridColumn != null)
            {
                if ((string) dataGridColumn.Header == "Holding Dates")
                {
                    // Show context menu for holding dates
                }
            }
        }
            // Other stuff
        else if (somethingElse)
        {
            // Show context menu for other stuff
        }
}