如何指定DataContext将ContextMenu添加到DataGridTemplateColumn?

时间:2016-02-05 19:44:00

标签: c# wpf data-binding contextmenu visual-tree

我正在以编程方式通过
烹饪DataGridTemplateColumns DataTemplate dtStringTemplate = (DataTemplate)XamlReader.Load(sr, pc); dataGridTemplateColumn.CellTemplate = dtStringTemplate;

我尝试将ContextMenu添加到DataGrid,但任何可编辑的单元格都使用自己的上下文菜单。

到目前为止,这篇文章让我得到TextBox上下文菜单按预期显示:How to add a ContextMenu in the WPF DataGridColumn in MVVM?

使用上面提到的帖子作为指南,我在App.xaml中创建了Style和ContextMenu;当我右键单击DataGrid中的Cell时,会出现我的上下文菜单。但是,我无法触发相关命令,我怀疑绑定不正确。这是App.xaml中的xaml:

<ContextMenu x:Key="DataGridContextMenu">
        <MenuItem Header="MenuItem One" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.CmdMenuItemOne}" />
        <MenuItem Header="MenuItem Two" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.CmdMenuItemOne}" />
    </ContextMenu>

DataGrid的DataContext是MyViewModel; MyViewModel有一个名为CmdMenuItemOne的公共DelegateCommand 不幸的是,从未调用过CmdMenuItemOne 我在绑定中误解了什么?谢谢......

2 个答案:

答案 0 :(得分:1)

使用下面给出的非常简单的方法。

<Window.Resources>
    <FrameworkElement x:Key="DCKey" />
</Window.Resources>

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = vm;

        ((FrameworkElement)this.Resources["DCKey"]).DataContext = vm;
    }

<MenuItem Header="DoSomething" Command="{Binding DataContext.Cmd, Source={StaticResource DCKey}}"/>

答案 1 :(得分:0)

由于ContextMenu不是DataGrid可视化树的一部分,我们无法访问DataGrid的DataContext中定义的属性。但我们可以采取下一个解决方法来做到这一点。

  1. 创建一个布尔附加属性来定义下一个东西;如果added属性的值为true,它将找到此属性附加到的对象的可视父级,并将父级的DataContext分配给此属性附加到的对象的Tag属性,另一方面如果值为附加属性为false,Tag属性将赋值为null。
  2. 创建一个扩展帮助器方法,该方法将扫描调用者的可视树,并将返回特定类型的父(调用者)父。
  3. 为DataGridCell对象创建默认样式,该对象将使用上面描述的依赖项属性并定义ContextMenu。在App.xaml中将此样式设置为资源(请注意,此样式将由项目中的所有DataGridCell对象使用)。
  4. 样式代码(应该在App.xaml中)

    <Style TargetType="DataGridCell">
            <Setter Property="dataGridCreateColumnAndBindIteFromCodeBehind:DataGridAttached.SetDataGridDataContextToTag" Value="True"></Setter>
             <Setter Property="ContextMenu">
                 <Setter.Value>
                    <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
                        <MenuItem Header="MenuItem One"
                                  Command="{Binding CmdMenuItemOne}" />
                        <MenuItem Header="MenuItem Two" 
                                  Command="{Binding CmdMenuItemTwo}" />
                    </ContextMenu>
                </Setter.Value>
             </Setter></Style>
    

    附加财产代码

    public class DataGridAttached
    {
    
        public static readonly DependencyProperty SetDataGridDataContextToTagProperty = DependencyProperty.RegisterAttached(
            "SetDataGridDataContextToTag", typeof (bool), typeof (DataGridAttached), new PropertyMetadata(default(bool), SetParentDataContextToTagPropertyChangedCallback));
    
        public static void SetSetDataGridDataContextToTag(DependencyObject element, bool value)
        {
            element.SetValue(SetDataGridDataContextToTagProperty, value);
        }
    
        public static bool GetSetDataGridDataContextToTag(DependencyObject element)
        {
            return (bool) element.GetValue(SetDataGridDataContextToTagProperty);
        }
    
        private static void SetParentDataContextToTagPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
        {
            PerformDataContextToTagAssignment(dependencyObject as FrameworkElement, (bool)args.NewValue);
        }
    
        private static void PerformDataContextToTagAssignment(FrameworkElement sender, bool isAttaching)
        {
            var control = sender;
            if (control == null) return;
            if (isAttaching == false)
            {
                control.Tag = null;
            }
            else
            {
                var dataGrid = control.FindParent<DataGrid>();
                if (dataGrid == null) return;
                control.Tag = dataGrid.DataContext;
            }
        }
    }
    

    帮助代码

    public static class VisualTreeHelperExtensions
    {
        public static T FindParent<T>(this DependencyObject child) where T : DependencyObject
        {
            while (true)
            {
                //get parent item
                DependencyObject parentObject = VisualTreeHelper.GetParent(child);
    
                //we've reached the end of the tree
                if (parentObject == null) return null;
    
                //check if the parent matches the type we're looking for
                T parent = parentObject as T;
                if (parent != null)
                    return parent;
                child = parentObject;
            }
        }
    }
    

    问候。