7

我的应用程序中有菜单。我正在使用分层数据模板对其进行可视化:

    <MenuItem Header="Main menu" ItemsSource="{Binding ApplicationMenu}" >
        <MenuItem.ItemTemplate>                    
            <HierarchicalDataTemplate DataType="{x:Type tm:RMenuItem}" 
                                      ItemsSource="{Binding Path=ChildrenItems}">                        
                <MenuItem Header="{Binding Name}" Command="{Binding RunOperationCommand}" />
            </HierarchicalDataTemplate>
        </MenuItem.ItemTemplate>
    </MenuItem>

菜单看起来应该如此,但不会触发每个菜单项的命令!更重要的是 - 它没有界限,这可以在调试器中看到:从未执行过获取 ICommand 属性的访问器。为什么会这样?

像往常一样工作完美:

<Menu>
    <MenuItem Header="SomeHeader" Command="{Binding RunOperationCommand}"/>
<Menu>
4

3 回答 3

7

您的问题中第一个和第二个示例之间的区别在于,在第二个代码片段中,您绑定MenuItem.Command到父级的数据上下文,该上下文已RunOperationCommand定义。而在第一个示例中,HierarchicalDataTemplate您将绑定到“本地”DataContext,这是一个菜单项。它没有适当的属性,因此绑定失败。

你有几个选择:

  • 一种是使用命令属性扩展您的菜单项,就像您在回答中所做的那样;
  • 绑定到可视树中的相对源,它具有命令的数据上下文,例如假设命令在您窗口的 DataContext 中:

    <MenuItem Header="Main menu" ItemsSource="{Binding ApplicationMenu}" >
        <MenuItem.ItemTemplate>                    
            <HierarchicalDataTemplate DataType="{x:Type tm:RMenuItem}" 
                                      ItemsSource="{Binding Path=ChildrenItems}">                        
                <MenuItem Header="{Binding Name}" 
                          Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.RunOperationCommand}" 
                />
            </HierarchicalDataTemplate>
        </MenuItem.ItemTemplate>
    </MenuItem>


<Window.Resources>
     <coreView:CommandReference x:Key="RunOperationCommand"
                                Command="{Binding RunOperationCommand}" />
</Window.Resources>

    <MenuItem Header="Main menu" ItemsSource="{Binding ApplicationMenu}" >
        <MenuItem.ItemTemplate>                    
            <HierarchicalDataTemplate DataType="{x:Type tm:RMenuItem}" 
                                      ItemsSource="{Binding Path=ChildrenItems}">                        
                <MenuItem Header="{Binding Name}" 
                          Command="{StaticResource RunOperationCommand}" 
                />
            </HierarchicalDataTemplate>
        </MenuItem.ItemTemplate>
    </MenuItem>
于 2009-12-21T14:08:35.430 回答
1

继续挖掘这个问题。我尝试过使用 ItemsContainer Style 的其他方式,在链接文本中进行了描述,因为 DataTemplate 在另一个 MenuItem 中创建了 MenuItem,这不是很好,而且它还为单击行为添加了一些人工制品。

<Menu Height="23" DockPanel.Dock="Top" ItemsSource="{Binding ApplicationMenu}" >
                <Menu.ItemContainerStyle>
                    <Style TargetType="{x:Type MenuItem}">
                        <Setter Property="Header" Value="{Binding Name}" />
                        <Setter Property="Command" Value="{Binding RunOperationCommand}"/>   
                        <Setter Property="CommandParameter" Value="123"/>
                        <Setter Property="ItemsSource" Value="{Binding ChildrenItems}" />
                    </Style>
                </Menu.ItemContainerStyle>
               <!--<MenuItem  />-->
</Menu>

我忘了提到 ApplicationMenu 是我的自定义 RMenuItem 类的可观察集合。所以这种方式也行,但是命令也行不通!!!但我注意到有趣的功能 - 如果我们通过 ItemsSource 设置 Menu 的源,如果我们静态添加 MenuItems(只是取消注释最后一行),命令绑定不起作用 - 在 ItemContainerStyle 中定义的命令绑定有效!-((为什么会这样????但这不是我的最终目标 - 我想基于一些具有分配 RoutedCommand 能力的集合来构建菜单机制(以便为 menuitem 提供热键)。使用 MVVM 方法使情况变得复杂:我的菜单项集合位于 ViewModel 层中,而 RoutedCommands 是 View 的功能,而我在 ViewModel 中使用简单的 ICommands。

于 2009-12-21T09:54:23.940 回答
1

似乎我已经找到了部分问题的解决方案。命令没有被绑定,因为我们似乎需要为每个菜单项创建特定的命令实例。核心问题是,我所有的菜单项几乎都执行相同的命令,不同之处仅在于命令参数的值。所以我应该这样做:

示例菜单项类:

public class RMyMenuItem
{
    public string Name { get; set; }

    public string InputGesture { get; set; }

    public ICommand ItemCommand
    { get; set; }

    public List<RMyMenuItem> ChildrenItems { get; set; }
}

ViewModel 中的属性:

public ObservableCollection<RMyMenuItem> ApplicationMenu
{
    get
    {
        //RApplicationMainMenu menu = new RApplicationMainMenu(0);
        //return new ObservableCollection<RMenuItem>(menu.Items);
        return new ObservableCollection<RMyMenuItem>()
        {
        new RMyMenuItem()
            {
                Name = "item1",                    
                ItemCommand = new DelegateCommand((param) => RunOperationExecute(param)),
                ChildrenItems = new List<RMyMenuItem>()
                {
        new RMyMenuItem()
        {
            Name = "item2",
            ItemCommand = new DelegateCommand((param) => RunOperationExecute(param))
        }
                }
            }
    };
    }

和 XAML:

    <Menu.ItemContainerStyle>
        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="Header" Value="{Binding Name}" />
            <Setter Property="MenuItem.Command" Value="{Binding ItemCommand}"/>   
            <Setter Property="MenuItem.CommandParameter" Value="123"/>
            <Setter Property="ItemsSource" Value="{Binding ChildrenItems}" />                    
        </Style>
    </Menu.ItemContainerStyle>
}
于 2009-12-21T13:01:48.110 回答