如何将 ViewModel(包括分隔符)正确绑定到 WPF 的菜单? [英] How to correctly bind a ViewModel (which Include Separators) to WPF's Menu?

查看:15
本文介绍了如何将 ViewModel(包括分隔符)正确绑定到 WPF 的菜单?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 MVVM 并且我想将我的 MenuViewModels 列表数据绑定到我的主要菜单.其中由一组菜单项和分隔符组成.

I'm using MVVM and I want to data bind my list of MenuViewModels to my maim menu. Which consists of a set of menu items and separators.

这是我的 MenuItemViewModel 代码:

Here's my MenuItemViewModel code:

public interface IMenuItemViewModel
{
}

[DebuggerDisplay("---")]
public class SeparatorViewModel : IMenuItemViewModel
{
}

[DebuggerDisplay("{Header}, Children={Children.Count}")]
public class MenuItemViewModel : IMenuItemViewModel, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public MenuItemViewModel(string header, ICommand command, ImageSource imageSource)
    {
        Header = header;
        Command = command;
        ImageSource = imageSource;

        Children = new List<IMenuItemViewModel>();
    }

    public string Header { get; private set; }
    public ICommand Command { get; private set; }

    public ImageSource ImageSource { get; private set; }

    public IList<IMenuItemViewModel> Children { get; private set; }
}

我的主窗口如下所示:

<Window.Resources>
    <HierarchicalDataTemplate DataType="{x:Type ViewModel:MenuItemViewModel}"
        ItemsSource="{Binding Children}">
        <MenuItem Header="{Binding Header}"
                  Command="{Binding Command}"/>
    </HierarchicalDataTemplate>

    <DataTemplate DataType="{x:Type ViewModel:SeparatorViewModel}">
        <Separator />
    </DataTemplate>
</Window.Resources>

<DockPanel>
    <Menu DockPanel.Dock="Top"
          ItemsSource="{Binding MenuItems}">
    </Menu>
</DockPanel>

应该是非常简单的东西.不幸的是,要么菜单项看起来不对,要么分隔符是一个空的 menuItem(取决于我的尝试).

Should be very simple stuff. Unfortunately, either the menu item looks wrong or the separator is an empty menuItem (depending on what I've tried).

那么,如何让我的 Menu 找到我的两个 DataTemplates?

So, how do I get my Menu to find my two DataTemplates?

推荐答案

解决了我自己的问题

在网上搜索了几个小时后,我发现了很多违背 WPF 的自然意图的例子,但没有一个能与它一起工作.

After spending several hours searching the web, I found lots of examples that work against the WPF's natural intentions but none that worked with it.

这里是如何使用Menu 控件而不是反对它...

Here's how to work with the Menu control and not against it...

一点背景

WPF 的 Menu 控件将通常自动创建 MenuItem 对象,当它绑定到 POCO 集合时,使用 ItemsSource 属性.

WPF's Menu control will normally auto create MenuItem objects for you when it is binded to a POCO collection, using the ItemsSource property.

但是,这个默认行为可以被覆盖!方法如下...

However, this default behavior can be overridden! Here's how...

解决方案

首先,您必须创建一个派生自 ItemContainerTemplateSelector 的类.或者使用我创建的简单类:

First, you must create a class that derives from ItemContainerTemplateSelector. Or use the simple class I've created:

public class MenuItemContainerTemplateSelector : ItemContainerTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, ItemsControl parentItemsControl)
    {
        var key = new DataTemplateKey(item.GetType());
        return (DataTemplate) parentItemsControl.FindResource(key);
    }
}

其次,您必须向 Windows resources 对象添加对 MenuItemContainerTemplateSelector 类的引用,如下所示:

Second, you must add a reference to the MenuItemContainerTemplateSelector class to your Windows resources object, like so:

<Window.Resources>
    <Selectors:MenuItemContainerTemplateSelector x:Key="_menuItemContainerTemplateSelector" />

第三,您必须在 MenuMenuItem 上设置两个属性(UsesItemContainerTemplateItemContainerTemplateSelector)>(在 HierarchicalDataTemplate 中定义).

Third, you must set two properties (UsesItemContainerTemplate, and ItemContainerTemplateSelector) on both the Menu and the MenuItem (which is defined in the HierarchicalDataTemplate).

像这样:

    <HierarchicalDataTemplate DataType="{x:Type ViewModel:MenuItemViewModel}"
        ItemsSource="{Binding Children}">
        <MenuItem Header="{Binding Header}"
                  Command="{Binding Command}"
                  UsesItemContainerTemplate ="true"
                  ItemContainerTemplateSelector=
                  "{StaticResource _menuItemContainerTemplateSelector}"/>
    </HierarchicalDataTemplate>

    <Menu DockPanel.Dock="Top"
          ItemsSource="{Binding MenuItems}"
          UsesItemContainerTemplate="True"
          ItemContainerTemplateSelector=
          "{StaticResource _menuItemContainerTemplateSelector}">
    </Menu>

为什么有效

出于优化目的,Menu 使用 UsesItemContainerTemplate 标志(默认值为 false)来跳过 DataTemplate 查找并返回一个普通的 MenuItem 对象.因此,我们需要将此值设置为 true,然后我们的 ItemContainerTemplateSelector 按预期工作.

For optimization purposes, the Menu uses the UsesItemContainerTemplate flag (which has a default value of false) to skip the DataTemplate lookup and just returns a normal MenuItem object. Therefore, we needed to set this value to true and then our ItemContainerTemplateSelector works as expected.

快乐编码!

这篇关于如何将 ViewModel(包括分隔符)正确绑定到 WPF 的菜单?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆