Закрепление команды в иерархическом datatemplate

У меня есть Меню в моем приложении. Я визуализирую его, используя иерархический шаблон данных:

    <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>
7
задан skaffman 21 December 2009 в 10:09
поделиться

3 ответа

Разница между первым и вторым примером в вашем вопросе заключается в том, что во втором фрагменте кода вы привязываете 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>
7
ответ дан 7 December 2019 в 03:16
поделиться

Похоже, я нашел решение части своей проблемы. Команда не является обязательной, потому что нам кажется, что нам нужно создать конкретный экземпляр команды для каждого пункта меню. Основная проблема заключается в том, что почти все мои элементы меню выполняют одну и ту же команду, а различия только в значении параметра команды. Поэтому я должен сделать так:

образец класса 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>
}
1
ответ дан 7 December 2019 в 03:16
поделиться

Продолжайте копать эту проблему. Я пробовал другой способ использования 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. Так что есть пища для размышлений ... -))

1
ответ дан 7 December 2019 в 03:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: