我的应用中有菜单。我正在使用分层数据模板将其可视化:
<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>
菜单看起来应该如此,但每个菜单项的Command都不会被触发!更多 - 它没有限制,可以在调试器中看到:ICommand属性的访问器从未被执行过。 为什么会这样?
照例做得很完美:
<Menu>
<MenuItem Header="SomeHeader" Command="{Binding RunOperationCommand}"/>
<Menu>
答案 0 :(得分:7)
您问题中第一个和第二个示例之间的区别在于,在第二个代码段中,您将MenuItem.Command
绑定到父级的数据上下文,其中定义了RunOperationCommand
。而在第一个带有HierarchicalDataTemplate
的示例中,您绑定到“本地”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>
答案 1 :(得分:1)
继续挖掘这个问题。我尝试过使用ItemsContainer Style的其他方式,在那里描述link text,因为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方法使情况变得复杂:我的menuitems集合驻留在ViewModel层中,而RoutedCommands是View的功能,而我在ViewModel中使用简单的ICommands。所以有一种值得思考的东西...... - ))
答案 2 :(得分:1)
似乎我找到了部分问题的解决方案。命令没有绑定,因为我们似乎需要为每个菜单项创建特定的命令实例。核心问题是,我的所有菜单项都执行相同的命令,差异仅在于命令参数的值。所以我应该这样做:
示例menuitem类:
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>
}