为项使用派生类型

本文关键字:派生 类型 | 更新日期: 2023-09-27 17:53:45

我有一个从MenuItem派生的类型。我希望在从MenuItem.ItemsSource生成子菜单项时使用该类型。

下面是一个XAML示例,它创建了一个正确类型的项,但将其包装在另一个MenuItem中。我想去掉换行菜单项。

    <MenuItem ItemsSource="{Binding MyItems}">
        <MenuItem.ItemTemplate>
            <DataTemplate>
                <local:MenuItemDerived Header="{Binding Name}" Property1="{Binding Prop1}" />
            </DataTemplate>
        </MenuItem.ItemTemplate>
    </MenuItem>

可以将生成的子类型更改为派生类型吗?

为项使用派生类型

通常,您只需要重写MenuItem控件模板来创建自定义项,而不是子类化MenuItem。但是,可以按照您的要求进行操作,并更改生成的子菜单项的类型。有两种方法可以做到这一点,这取决于您的用例。

  1. 为菜单中的每种类型的项目设置ItemContainerTemplate。假设您正在用一个名为MyItem的类的实例填充它,您可以这样做:

    <MenuItem Header="Test" UsesItemContainerTemplate="True" ItemsSource="{Binding Items}">
        <MenuItem.Resources>
            <ItemContainerTemplate
                DataType="{x:Type local:MyItem}">
                <local:MenuItemDerived />
            </ItemContainerTemplate>
        </MenuItem.Resources>
    </MenuItem>
    

    你可以在那里添加你想要的,每一个类型的项目,可以在菜单中(通常只有一个)。

  2. 使用ItemContainerTemplateSelector来使用您想要选择模板的任何自定义逻辑。如果您只是希望每个生成的项都使用相同的菜单项类型,这是很好的,因为第一个选项不允许这样做(您不能使用Object作为数据模板的数据类型)。如果您想基于自定义逻辑来选择模板,这比检查项的类型要复杂得多,这也是必要的。

    <MenuItem Header="Test" UsesItemContainerTemplate="True" ItemsSource="{Binding Items}">
        <MenuItem.ItemContainerTemplateSelector>
            <local:MenuItemContainerTemplateSelector>
                <DataTemplate>
                    <local:MenuItemDerived />
                </DataTemplate>
            </local:MenuItemContainerTemplateSelector>
        </MenuItem.ItemContainerTemplateSelector>
    </MenuItem>
    
    我在这里使用的非常简单的MenuItemContainerTemplateSelector类看起来像这样:
    [ContentProperty("Template")]
    internal class MenuItemContainerTemplateSelector : ItemContainerTemplateSelector
    {
        public DataTemplate Template { get; set; }
        public override DataTemplate SelectTemplate(object item, ItemsControl parentItemsControl)
        {
            return Template;
        }
    }
    

    当然,如果你愿意,你也可以创建一个包含多个模板的复杂选择器。

注意在这两种情况下UsesItemContainerTemplate属性的使用。对于任何自定义项容器模板,