【问题标题】:Command Binding in hierarchical datatemplate分层数据模板中的命令绑定
【发布时间】:2010-12-28 00:51:03
【问题描述】:

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

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

【问题讨论】:

    标签: .net binding command hierarchicaldatatemplate


    【解决方案1】:

    您问题中第一个和第二个示例之间的区别在于,在第二个代码 sn-p 中,您将 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>
    

    【讨论】:

    • 感谢您的回复。关于您对“父母”和“本地”数据上下文的想法。我不明白他们为什么不同。我认为菜单和菜单项应该派生父数据上下文。数据上下文不是依赖属性的特性之一吗?
    • 如果菜单和菜单项具有相同的数据上下文,则 {Binding Name} 将始终绑定到该公共数据上下文中的相同属性 Name。但是您希望 Name 绑定到实际菜单项的实体。因此 {Binding RunOperationCommand} 具有相同的效果,它在菜单项上搜索 RunOperationCommand。它回答了你的问题吗?
    【解决方案2】:

    继续挖掘这个问题。我尝试了使用 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 方法使情况变得复杂:我的菜单项集合位于 ViewModel 层中,而 RoutedCommands 是 View 的功能,而我在 ViewModel 中使用简单的 ICommands。所以有一个值得深思的地方...-))

    【讨论】:

      【解决方案3】:

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

      示例菜单项类:

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

      【讨论】:

        猜你喜欢
        • 2012-07-26
        • 2017-04-28
        • 1970-01-01
        • 2017-02-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多