如何向动态生成的ContextMenu中的项添加命令

时间:2016-01-28 16:17:31

标签: c# wpf xaml data-binding

我有一个从ObservableCollection填充的上下文菜单。我希望用户能够点击任何这些项目,然后调用一个方法将所点击的项目的文本作为参数传递。

我开始关注this question的回答。但是,我的控制台输出中出现错误,我的方法没有被调用。

  

System.Windows.Data错误:40:BindingExpression路径错误:在'object'''MenuItem'(Name ='myMenu')'上找不到'FunctionToCall'属性。 BindingExpression:路径= FunctionToCall; DataItem ='MenuItem'(Name ='myMenu'); target元素是'MenuItem'(Name =''); target属性是'Command'(类型'ICommand')

这是我的xaml

            <MenuItem Name="myMenu" Header="display text" ItemsSource="{Binding}" >
                <MenuItem.ItemContainerStyle>
                    <Style TargetType="MenuItem">
                        <Setter Property="Command" Value="{Binding FunctionToCall, RelativeSource={RelativeSource AncestorType=MenuItem}}"/>
                        <Setter Property="CommandParameter" Value="{Binding}"/>
                    </Style>
                </MenuItem.ItemContainerStyle>
            </MenuItem>

我的视图模型代码

    RelayCommand _command;
    public ICommand FunctionToCall
    {
        get
        {
            if (_command == null)
            {

                _command = new RelayCommand(p => this.InnerMethod(p));
            }
            return _command ;
        }
    }
    public void InnerMethod(object parameter)
    {
        ....

另一个答案建议在Binding中添加一个或两个DataContexts,我试过这个但我仍然得到相同的错误,尽管它说找不到DataContext属性而不是FunctionToCall。

我找到了RelayCommand here的定义。

2 个答案:

答案 0 :(得分:1)

真正的问题在于绑定。使用MenuItem的 DataContext属性实际访问ViewModel实例

<MenuItem Name="myMenu" Header="display text" ItemsSource="{Binding}" >
   <MenuItem.ItemContainerStyle>
        <Style TargetType="MenuItem">
           <Setter Property="Command" Value="{Binding DataContext.FunctionToCall, RelativeSource={RelativeSource AncestorType=MenuItem}}"/>
            <Setter Property="CommandParameter" Value="{Binding}"/>
         </Style>
   </MenuItem.ItemContainerStyle>
 </MenuItem>

MenuItem将ViewModel作为DataContext。实际上我们想要..

  

MenuItem.DataContext.FunctionToCall

希望你不需要不同的菜单项来绑定不同的命令,否则你必须稍微改变你的设计。

根据您的评论:

您需要List<MenuItem> MenuItems与ContextMenu ItemSource属性绑定为

public class MenuItem
{
    public string Header { get; set; }

    public ICommand Command { get; set; }
}

<强> XAML:

<ContextMenu ItemsSource="{Binding MenuItems}" >
        <ContextMenu.ItemContainerStyle>
            <Style TargetType="{x:Type MenuItem}" >
                <Setter Property="Header" Value="{Binding Header}"/>
                <Setter Property="Command" Value="{Binding Command}" />
            </Style>
        </ContextMenu.ItemContainerStyle>
    </ContextMenu>

并根据您的想法在ViewModel中添加所需的上下文菜单项。

答案 1 :(得分:-1)

这是怎么做的。

public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new ViewModel();
        }

XAML

<MenuItem Header="{Binding Item1}" Command="{Binding FunctionToCall}" CommandParameter="{Binding Header, RelativeSource={RelativeSource Self}}"/>

视图模型

public class ViewModel
    {
        ICommand _cmd = new CustomCommand();
        public ICommand FunctionToCall
        {
            get { return _cmd; }
            set { _cmd = value; }
        }

        public string Item1 { get; set; }

        public ViewModel() { Item1 = "1Header"; }
    }

命令

public class CustomCommand : ICommand
{
    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        MessageBox.Show(parameter.ToString());
    }
}

因此,假设您希望将Header MenuItem作为参数传递给您的命令,请执行以下更改:

<Setter Property="Command" Value="{Binding FunctionToCall}"/>
<Setter Property="CommandParameter" Value="{Binding Header, RelativeSource={RelativeSource Self}}"/>