如何从ItemTemplate中将Command绑定到ContextMenu?

时间:2016-03-16 18:08:51

标签: c# wpf contextmenu itemtemplate

我想将某个命令绑定到menuItem。所述菜单项是在ContextMenu内定义的ItemTemplate的一部分。

现在,我编译并运行,但命令永远不会被调用。在过去,我使用了类似的模式将命令挂钩到ItemTemplate中定义的按钮并成功。

任何人都知道如何才能做到这一点?

XAML:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Wpf_treeView" x:Name="window" x:Class="Wpf_treeView.MainWindow"
    Title="MainWindow" Height="350" Width="525">
  <Grid>
    <TreeView HorizontalAlignment="Left" Height="299" Margin="10,10,0,0" VerticalAlignment="Top" Width="228" ItemsSource="{Binding DataInfosView}" >
      <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Children}">
          <TextBlock DockPanel.Dock="Left" Text="{Binding InfoValue}" TextAlignment="Left" >
            <TextBlock.ContextMenu>
              <ContextMenu>
                <MenuItem Header="{Binding InfoValue}" IsEnabled="False"/>
                <MenuItem Header="Add child" Command="{Binding AddChildCmd, ElementName=window}"/>
              </ContextMenu>
            </TextBlock.ContextMenu>
          </TextBlock>
        </HierarchicalDataTemplate>
      </TreeView.ItemTemplate>
    </TreeView>
  </Grid>
</Window>

C#:

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;

namespace Wpf_treeView
{
    public partial class MainWindow : Window
    {
        private static readonly Random rnd = new Random();
        private List<InfoData> m_InfoData = new List<InfoData>();

        public ListCollectionView DataInfosView { get; private set; }

        public static readonly DependencyProperty AddChildProperty =
            DependencyProperty.Register("AddChildCmd", 
                                        typeof(ICommand),
                                        typeof(MainWindow));

        public ICommand AddChildCmd
        {
            get { return (ICommand) GetValue(AddChildProperty); }
            set { SetValue(AddChildProperty, value); }
        }

        public MainWindow()
        {
            AddChildCmd = new RoutedCommand();
            CommandManager.RegisterClassCommandBinding(
                GetType(), 
                new CommandBinding(AddChildCmd, AddChild));

            m_InfoData.Add(new InfoData(4));
            m_InfoData.Add(new InfoData(1));
            m_InfoData.Add(new InfoData(5));
            m_InfoData[1].Children.Add(new InfoData(3));
            m_InfoData[1].Children[0].Children.Add(new InfoData(7));

            DataInfosView = new ListCollectionView(m_InfoData);
            DataContext = this;

            InitializeComponent();
        }

        private void AddChild(object sender, RoutedEventArgs e)
        {
            ExecutedRoutedEventArgs args = (ExecutedRoutedEventArgs)e;
            InfoData info = (InfoData)args.Parameter;
            info.Children.Add(new InfoData(rnd.Next(0, 11)));
        }
    }

    class InfoData : INotifyPropertyChanged
    {
        private int infoValue;

        public int InfoValue
        {
            get { return infoValue; }
            set
            {
                if (value != infoValue)
                {
                    infoValue = value;
                    OnPropertyChanged();
                }
            }
        }

        public List<InfoData> Children { get; private set; }

        public InfoData(int infoValue)
        {
            InfoValue = infoValue;
            Children = new List<InfoData>();
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(
            [CallerMemberName] string propertyName = null)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

1 个答案:

答案 0 :(得分:1)

好的,这应该有效:

<TextBlock DockPanel.Dock="Left"
                           Text="{Binding InfoValue}"
                           TextAlignment="Left"
                           Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
                    <TextBlock.ContextMenu>
                        <ContextMenu>
                            <MenuItem Header="{Binding InfoValue}"
                                      IsEnabled="False" />
                            <MenuItem Header="Add child"
                                      Command="{Binding Path=Parent.PlacementTarget.Tag.AddChildCmd, RelativeSource={RelativeSource Self}}" 
                                      CommandParameter="{Binding}" />
                        </ContextMenu>
                    </TextBlock.ContextMenu>
                </TextBlock>

ContextMenu并不存在于常规的Visual Tree中,因此您无法走到树上以进入主数据上下文。通过使用标签,您可以传入&#34;主窗口的数据上下文到上下文菜单。有关使用上下文菜单进行绑定的更多信息,请参阅this answer以及this one,因为它们提供了有关正在发生的事情的一些很好的解释