Command Binding in hierarchical datatemplate

前端 未结 3 503
遇见更好的自我
遇见更好的自我 2021-02-06 09:45

I have Menu in my app. I\'m visualizing it using hierarchical data template:

             


        
相关标签:
3条回答
  • 2021-02-06 10:03

    Seems like I've found solution for part of my problem. Command is not being binding because, it seems like we need to create particular instance of command for each menu item. The core problem is that, allmost all my menuitems execute the same command and differences are only in value of command parameter. So I should do so:

    sample menuitem class:

    public class RMyMenuItem
    {
        public string Name { get; set; }
    
        public string InputGesture { get; set; }
    
        public ICommand ItemCommand
        { get; set; }
    
        public List<RMyMenuItem> ChildrenItems { get; set; }
    }
    

    property in 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))
            }
                    }
                }
        };
        }
    

    And 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>
    }
    
    0 讨论(0)
  • 2021-02-06 10:14

    Continue digging this problem. I've tried other way using ItemsContainer Style, described there link text, because DataTemplate creates MenuItem within another MenuItem, which is not pretty good and it also adds some artefacts to clicking behavior.

    <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>
    

    I've forgotten to mention that ApplicationMenu is an observable collection of my custom RMenuItem class. So this way also works, but commands don't work either!!! BUT I've noticed interesting feature - command binding don't works if we setting Menu's source via ItemsSource, if we add MenuItems statically (just uncommenting last line) - command binding defined in ItemContainerStyle works!!! -(( Why it happens so???? But it is not my ending aim - I'd like to make mechanism of building menu based on some collection with ability of assigning RoutedCommand (in order to have hot-key for menuitem). The situation is being complicated by using MVVM approach: my collection of menuitems resides in ViewModel layer, while RoutedCommands is a View's feature, while I'm using simple ICommands in my ViewModel. So there is a food for thought ... -))

    0 讨论(0)
  • The difference between the first and the second example in your question is that in the second code snippet you are binding MenuItem.Command to the parent's data context, which has the RunOperationCommand defined. Whereas in the first example with the HierarchicalDataTemplate you are binding to the "local" DataContext, which is a menu item. It doesn't have the appropriate property, so the binding fails.

    You have several options:

    • one is to extend your menu items with the command property, like you did in your answer already;
    • bind to the relative source up in the visual tree, which has the data context with the command, e.g. assuming that the command is in your window's 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>
    

    • Make a StaticResource from your command, similar to this blog post approach

    <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>
    
    0 讨论(0)
提交回复
热议问题