【问题标题】:WPF XAML - MenuItem with ItemSource and sub menu itemsWPF XAML - 带有 ItemSource 和子菜单项的 MenuItem
【发布时间】:2016-02-29 06:16:44
【问题描述】:

我在上下文菜单中有一个 MenuItem,我想使用 ItemSource 为列表中的每个项目生成子菜单项。然后,每个生成的项目都应该有子菜单项活动(可检查)、编辑和删除。

Custom Messages
    -Custom Message 1
           -Active 
           -Edit
           -Delete
    -Custom Message 2
           -Active 
           -Edit
           -Delete
    -Custom Message 3
           -Active 
           -Edit
           -Delete

以下 XAML 部分有效:

<MenuItem Header="Custom Messages" Visibility="{Binding Path=HasCustomMessages, Converter={StaticResource BVC}}" ItemsSource="{Binding Path=CustomMessages}" DisplayMemberPath="Description">
    <MenuItem.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Setter Property="ItemsSource">
                <Setter.Value>
                    <x:Array Type="FrameworkElement">
                        <MenuItem Header="Active" IsCheckable="True" IsChecked="{Binding Path=Active}"></MenuItem>
                        <Separator></Separator>
                        <MenuItem Header="Edit" Name="EditCustomMessageButton" Click="EditCustomMessageButton_Click" Style="{x:Null}"></MenuItem>
                        <MenuItem Header="Delete" Name="DeleteCustomMessageButton" Click="DeleteCustomMessageButton_Click" Style="{x:Null}"></MenuItem>
                    </x:Array>
                </Setter.Value>
            </Setter>
        </Style>
    </MenuItem.ItemContainerStyle>                       
</MenuItem>
<MenuItem Header="Add Custom Message" Name="AddCustomMessageButtton" Click="AddCustomMessageButtton_Click"></MenuItem>
<Separator></Separator>
<MenuItem Header="Delete" Name="DeleteButton" Click="DeleteButton_Click"></MenuItem>

但是有两个问题:

  1. Edit 和 Delete 似乎以一种重复的方式表现,因为它们似乎都有子菜单,然后在悬停时抛出和异常:

  2. 通过在编辑和删除上设置 ItemSource="{x:Null}" 可以解决上述问题,但事件的行为很奇怪。单击 Delete 不会执行任何操作,单击 Edit 会触发 Edit 按钮单击事件,然后触发 Delete 按钮单击事件,然后是 Add 按钮单击事件(这甚至不是其他两个按钮的同级)。

【问题讨论】:

  • 是否可以为每个包含 Click 事件的 ICommand 属性的 menuItem 拥有一个 VM?

标签: .net wpf xaml


【解决方案1】:

问题是您将所有MenuItem 的样式设置为与子菜单相同,从而导致此无限递归 - StackOverflow :-) 问题。 以下行是错误的:

<Style TargetType="MenuItem">

因此,您可以在资源中创建此样式并通过其 x:Key 调用它:

<Style x:Key="SubMenuStyle">
    <Setter Property="ItemsSource">
        <Setter.Value>
            <x:Array Type="FrameworkElement">
                <MenuItem Header="Active" IsCheckable="True" IsChecked="{Binding Path=Active}"></MenuItem>
                <Separator></Separator>
                <MenuItem Header="Edit" Name="EditCustomMessageButton" Click="EditCustomMessageButton_Click" Style="{x:Null}"></MenuItem>
                <MenuItem Header="Delete" Name="DeleteCustomMessageButton" Click="DeleteCustomMessageButton_Click" Style="{x:Null}"></MenuItem>
            </x:Array>
        </Setter.Value>
    </Setter>
</Style>


<MenuItem Header="Custom Messages" ItemsSource="{Binding Path=CustomMessages}" ItemContainerStyle="{StaticResource SubMenuStyle}"...>

【讨论】:

  • 这似乎没有解释如何在生成的菜单项上实现子项。你能澄清一下吗?我在原始问题中添加了一个图表来解释我想要实现的目标
  • 我认为你可以将每个CustomMessage的ControlTemplate设置为ListBox
  • 我不确定列表框在这里有什么帮助?
  • 我已将其更新为类似于您所做的解决方案,但没有递归(使用 x:Key)
  • 知道了,效果很好,我唯一需要做的就是使用 EventSetters 设置 Click 事件处理程序。
【解决方案2】:

首先,您在上面的代码中将 ItemsSource 属性设置为 ItemsSource="{Binding Path=CustomMessages}" 两次。

其次,您以错误的方式设置 ItemsSource。应该是:

<MenuItem ...>
<MenuItem.ItemsSource>
 <x:Array Type="FrameworkElement">
   <MenuItem Header="Active" IsCheckable="True" IsChecked="{Binding Path=Active}"></MenuItem>
   <Separator></Separator>
   <MenuItem Header="Edit" Name="EditCustomMessageButton" Style="{x:Null}"></MenuItem>
   <MenuItem Header="Delete" Name="DeleteCustomMessageButton" Style="{x:Null}"></MenuItem>
 </x:Array>
</MenuItem.ItemsSource>

【讨论】:

  • 需要为第一级项目(从模型中的集合生成)设置两个项目源,然后为底层静态项目(活动、编辑、删除)设置第二个源
  • 第二个 ItemSource 在 MenuItem.ItemContainerStyle 上,这是生成的子菜单项的样式。
【解决方案3】:

这里的答案对我根本不起作用。有效的是来自this answer 的方法。

我所做的是像这样创建了一个简单的模板选择器:

公共类 MenuItemContainerTemplateSelector : ItemContainerTemplateSelector
{
    公共字符串 TemplateKey { 获取;放; }

    公共覆盖 DataTemplate SelectTemplate(object item, ItemsControl parentItemsControl)
    {
        return (DataTemplate) parentItemsControl.FindResource(TemplateKey);
    }
}

那么整个菜单结构看起来是这样的:

<Menu>
    <Menu.Resources>
        <DataTemplate x:Key="ItemWithSubmenu" DataType="{x:Type ItemViewModel}">
            <MenuItem Header="{Binding HeaderProperty}">
                <MenuItem Header="Active" IsCheckable="True" IsChecked="{Binding Path=Active}" />
                <Separator />
                <MenuItem Header="Edit" Click="EditCustomMessageButton_Click" />
                <MenuItem Header="Delete" Command="{Binding DeleteCommand}" />
            </MenuItem>
        </DataTemplate>

        <main:MenuItemContainerTemplateSelector TemplateKey="ItemWithSubmenu" x:Key="ItemWithSubmenuSelector" />
    </Menu.Resources>

    ...
    <MenuItem Header="Custom Messages" ItemsSource="{Binding CustomMessages}" ItemContainerTemplateSelector="{StaticResource ItemWithSubmenuSelector}" UsesItemContainerTemplate="True" />
    ...
</Menu>

【讨论】:

    猜你喜欢
    • 2023-03-27
    • 2013-07-14
    • 2014-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-22
    • 2010-12-18
    • 1970-01-01
    相关资源
    最近更新 更多