Wpf 为什么我的菜单项在覆盖DataTemplate时有图标?

Wpf 为什么我的菜单项在覆盖DataTemplate时有图标?,wpf,xaml,datatrigger,Wpf,Xaml,Datatrigger,我已经成功地实现了一个WPF菜单,其中顶级项被绘制为大按钮,而较低级别项被绘制为标准菜单项(请参阅我前面的问题和) 在我最初的尝试中,我的低级项模板(SubItemTemplate,在下面的示例中)包含一个图像和一个文本块。结果是看起来像一个普通的菜单项,有一个空的图标区域和菜单项文本部分文本旁边的图像。我不希望在可视化显示中看到图标区域,因为我认为整个可视化显示将由模板的内容决定。顶级模板(TopLevelItemTemplate)没有任何可见的空图标区域 当我从较低级别的模板中删除图像,并将

我已经成功地实现了一个WPF菜单,其中顶级项被绘制为大按钮,而较低级别项被绘制为标准菜单项(请参阅我前面的问题和)

在我最初的尝试中,我的低级项模板(
SubItemTemplate
,在下面的示例中)包含一个图像和一个文本块。结果是看起来像一个普通的菜单项,有一个空的图标区域和菜单项文本部分文本旁边的图像。我不希望在可视化显示中看到图标区域,因为我认为整个可视化显示将由模板的内容决定。顶级模板(
TopLevelItemTemplate
)没有任何可见的空图标区域

当我从较低级别的模板中删除图像,并将其替换为图标属性的样式设置器时,我得到了我想要的显示

我不理解Icon属性如何以及为什么存在于我的较低级别的item DataTemplate上

这是我的密码。属性
HasParent
用于区分非顶级菜单项(即使用
子项模板绘制的菜单项)。我不理解的部分是DataTrigger

为什么触发器中有可用的图标属性

<UserControl.Resources>
    <Image x:Key="MenuIconResource16" Height="16" Width="16" Source="{Binding Icon32}" x:Shared="False" />

    <HierarchicalDataTemplate x:Key="TopLevelItemTemplate" ItemsSource="{Binding Children}">
        <StackPanel VerticalAlignment="Bottom" Orientation="Vertical">
            <Image Width="32" Height="32" VerticalAlignment="Center" Source="{Binding Icon32}" ToolTip="{Binding UserHint}" />
            <TextBlock Text="{Binding Name}"/>
        </StackPanel>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate x:Key="SubItemTemplate" ItemsSource="{Binding Children}">
        <TextBlock Text="{Binding Name}"/>
    </HierarchicalDataTemplate>
</UserControl.Resources>

<WrapPanel Height="Auto">
   <Menu ItemsSource="{Binding DataContext.EventMenu.TopLevel, ElementName=UserControl}" ItemTemplateSelector="{StaticResource MenuItemTemplateSelector}">
       <Menu.ItemContainerStyle>
           <Style TargetType="{x:Type MenuItem}">
               <Setter Property="Command" Value="{Binding Command}" />
               <Setter Property="CommandParameter" Value="{Binding EventType}"/>
               <Style.Triggers>
                   <DataTrigger Binding="{Binding HasParent}" Value="true">
                       <Setter Property="Icon" Value="{StaticResource MenuIconResource16}"/>
                   </DataTrigger>
               </Style.Triggers>
           </Style>
       </Menu.ItemContainerStyle>
   </Menu>
</WrapPanel>

我认为整个视觉显示将由模板的内容决定

@dkozl指出了
DataTemplate
Template
之间的区别——这是重要的区别。数据模板是拥有的控件用作整体控件一部分的XAML片段,它可能包括也可能不包括其他(可自定义或硬编码)可视元素和/或其他数据模板。控件模板是定义该控件可视结构的地方。如果设置/覆盖控件模板,则不希望看到任何其他视觉内容的预期将成立

顶级模板(
TopLevelItemTemplate
)没有任何可见的空图标区域

这里需要注意的另一点是,
菜单的默认样式为其
菜单项定义了多个控件模板。根据角色“TopLevelHeader”、“TopLevelItem”、“SubmonuHeader”和“SubmonuItem”应用这些模板。因此,您将看到这些不同菜单项的不同行为。看一看,这应该很有启发性(尽管它们有点复杂)

为什么触发器中有可用的图标属性

<UserControl.Resources>
    <Image x:Key="MenuIconResource16" Height="16" Width="16" Source="{Binding Icon32}" x:Shared="False" />

    <HierarchicalDataTemplate x:Key="TopLevelItemTemplate" ItemsSource="{Binding Children}">
        <StackPanel VerticalAlignment="Bottom" Orientation="Vertical">
            <Image Width="32" Height="32" VerticalAlignment="Center" Source="{Binding Icon32}" ToolTip="{Binding UserHint}" />
            <TextBlock Text="{Binding Name}"/>
        </StackPanel>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate x:Key="SubItemTemplate" ItemsSource="{Binding Children}">
        <TextBlock Text="{Binding Name}"/>
    </HierarchicalDataTemplate>
</UserControl.Resources>

<WrapPanel Height="Auto">
   <Menu ItemsSource="{Binding DataContext.EventMenu.TopLevel, ElementName=UserControl}" ItemTemplateSelector="{StaticResource MenuItemTemplateSelector}">
       <Menu.ItemContainerStyle>
           <Style TargetType="{x:Type MenuItem}">
               <Setter Property="Command" Value="{Binding Command}" />
               <Setter Property="CommandParameter" Value="{Binding EventType}"/>
               <Style.Triggers>
                   <DataTrigger Binding="{Binding HasParent}" Value="true">
                       <Setter Property="Icon" Value="{StaticResource MenuIconResource16}"/>
                   </DataTrigger>
               </Style.Triggers>
           </Style>
       </Menu.ItemContainerStyle>
   </Menu>
</WrapPanel>

样式触发器能够修改其应用于的控件的任何依赖项属性。由于所讨论的样式触发器正在应用于
MenuItem
控件,因此它可以修改该控件所拥有的。

创建
MenuItem
包装时,您在
DataTemplate
中放入的所有内容都将在
MenuItem.Content
中使用。因此,当您放入
DataTemplate
is时,它将变成
Content
,当您在
Style
中设置它时,您将设置
MenuItem
包装器的
图标
属性,并且
DataTemplate
提供内容。如果要更改
MenuItem
的显示方式,则必须更改
MenuItem.Template
,默认情况下,顶层菜单和子菜单的显示方式不同。谢谢!WPF的复杂性中似乎嵌套着复杂性。问题:我必须引入一个属性(
HasParent
),该属性仅用于触发样式(在两个模板之间选择的DataTemplateSelector中)。是否有任何方法可以访问您描述的角色(
TopLevelItem
,等等),以便从我的模型中删除不必要的属性?@larrylusting不确定我是否理解,但您应该能够使用
Binding RelativeSource=TemplatedParent从控制模板访问
角色
属性,Path=Role
,并使用
Binding RelativeSource={RelativeSource antestortype=MenuItem},Path=Role
从控件内的数据模板。