У меня есть Меню в моем приложении. Я визуализирую его, используя иерархический шаблон данных:
<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>
меню похоже, как оно должно, но Команда для каждого пункта меню не запущена! Еще более - это не ограничено, который был виден в отладчике: доберитесь accessor Собственности ICommand никогда не выполнялся. Почему это происходит так?
Выполнение как обычные прекрасные работы:
<Menu>
<MenuItem Header="SomeHeader" Command="{Binding RunOperationCommand}"/>
<Menu>
Разница между первым и вторым примером в вашем вопросе заключается в том, что во втором фрагменте кода вы привязываете 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>
Похоже, я нашел решение части своей проблемы. Команда не является обязательной, потому что нам кажется, что нам нужно создать конкретный экземпляр команды для каждого пункта меню. Основная проблема заключается в том, что почти все мои элементы меню выполняют одну и ту же команду, а различия только в значении параметра команды. Поэтому я должен сделать так:
образец класса 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>
}
Продолжайте копать эту проблему. Я пробовал другой способ использования 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, если мы добавляем MenuItems статически (просто раскомментируя последнюю строку) - привязка команды, определенная в ItemContainerStyle, работает !!! - ((Почему так происходит ???? Но это не моя конечная цель - я хотел бы сделать механизм построения меню на основе некоторой коллекции с возможностью назначения RoutedCommand (чтобы иметь горячую клавишу для элемента меню). Ситуация усложняется использованием подхода MVVM: моя коллекция элементов меню находится на уровне ViewModel, а RoutedCommands - это функция View, а я использую простые ICommands в моей ViewModel. Так что есть пища для размышлений ... -))