【问题标题】:Specify Command for MenuItem in a DataTemplate在 DataTemplate 中为 MenuItem 指定命令
【发布时间】:2010-10-28 06:49:13
【问题描述】:

我有一个上下文菜单。它绑定到某个集合,并且它有一个像这样定义的 ItemTemplate:

<ContextMenu
    ItemsSource={Binding ...}
    ItemTemplate={StaticResource itemTemplate}
    />

itemTemplate 是一个带有 TextBlock 的简单 DataTemplate:

<DataTemplate x:Key="itemTemplate">
    <TextBlock Text={Binding ...} />
</DataTemplate>

如何将 MenuItem 的 Command 属性绑定到底层对象的属性?

【问题讨论】:

    标签: wpf datatemplate command


    【解决方案1】:

    我意识到我在事后回答了这个问题,但我遇到了同样的问题,以前的答案似乎使绑定到多个不同的命令变得困难。我得到的解决方案与 MatrixManAtYrService 的非常相似,分为 3 个部分:

    1) 使用 ItemContainerStyle 属性将命令绑定到 ViewModel 中的命令——这与前面的答案相同。一个例外是我将 CommandParameter 绑定到 MenuItem。

    <Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource Self}}"/>
    

    2) 创建一个自定义类来定义每个 MenuItem 的外观和行为。菜单的 ItemsSource 将设置为这些列表。这与其他答案相同。但是,在我的实现中,我为类提供了一个 Action,以便在调用 MenuItemCommand 时执行。我还包括了一个布尔值,它将允许 MenuItem 被禁用。

    public class MenuAction
    {
        public string Name { get => name; set => name = value; }
        public Action Action { get => action; set => action = value; }
        public bool CanExecute { get => canExecute; set => canExecute = value; }
    }
    

    3) 在命令实现中将控制路由到 MenuAction 中的代表。

    public void HandleCommand(object sender)
    {
        MenuItem clickedMenuItem = sender as MenuItem;
        MenuAction menuAction = clickedMenuItem?.DataContext as MenuAction;
        if(menuAction != null)
            menuAction.Action();
    }
    
    public bool CanMenuItemExecute(object sender)
    {
        MenuItem clickedMenuItem = sender as MenuItem;
        MenuAction menuAction = clickedMenuItem?.DataContext as MenuAction;
        if (menuAction != null)
            return menuAction.CanExecute;
        else
            return false;
    }
    
    

    这应该允许您在列表中定义命令的所有行为。虽然它在技术上绑定到单个命令,但它在功能上类似于拥有多个不同的命令。同样的方法也应该适用于嵌套的 MenuItems 和 HierarchicalDataTemplates,但需要进行一些调整。

    【讨论】:

      【解决方案2】:

      虽然这只是对 Martin Harris 的回答略有不同,但我想我还是会分享它。我发现为整个集合指定单个命令并发送命令参数更有用:

      <MenuItem.ItemContainerStyle>
          <Style TargetType="MenuItem">
             <Setter Property="Command" Value="{x:Static v:ViewModel.CommandForAll}"/>
             <Setter Property="CommandParameter" Value="{Binding ValueForCommand}"/>
          </Style>
      </MenuItem.ItemContainerStyle>
      

      然后你可以确定在命令的处理程序中做什么:

      private void CommandForAll_Executed(object sender, ExecutedRoutedEventArgs e)
      {
          var cmdParam = e.Paramater as ExpectedType
          if (cmdParam != null)
              //DoStuff...
      }
      

      【讨论】:

        【解决方案3】:

        我认为您需要将 TextBlock 包装在 MenuItem 中:

        <DataTemplate x:Key="itemTemplate">
            <MenuItem Command={Binding ...}>
                <TextBlock Text={Binding ...} />
            </MenuItem>
        </DataTemplate>
        

        但我现在没有 IDE 来尝试这个。告诉我进展如何。


        看起来您需要使用 here 所见的 ItemContainerStyle。很抱歉一开始就让你走错了路——但我遇到了一个 IDE,这很有效:

        <ContextMenu.ItemContainerStyle>
            <Style TargetType="MenuItem">
                <Setter Property="Command" Value="{Binding ...}"/>
            </Style>
        </ContextMenu.ItemContainerStyle>
        

        【讨论】:

        • 实际上,这会将 TextBlock 添加到 MenuItem 的 Items 集合中。它还将 MenuItem 放在另一个 MenuItem 中。
        • 这会创建双 MenuItem,这会破坏样式!不要认为这是一个合适的答案!
        • @Kolky - 阅读我更正自己的答案的第二部分。我没有删除不正确的前半部分,因为它已经被评论了。
        • 对不起,我的第一反应;第二个解决方案确实有效。
        • 如果有多个菜单项,我们需要将菜单项与单独的命令绑定。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-28
        相关资源
        最近更新 更多