2015-07-03 20 views
5

我正在使用MVVM,我想将我的列表MenuViewModels的数据绑定到我的主菜单。它由一组菜单项和分隔符组成。如何将ViewModel(包含分隔符)正确绑定到WPF的菜单?

这里是我的MenuItemViewModel代码:

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(取决于我所尝试的)。

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

回答

10

解决我自己的问题

花费几个小时在网上搜索后,我发现很多的工作的WPF的自然的意图,但没有与它合作的例子。

这里是如何工作的Menu控制,而不是针对它...

一点背景

WPF的Menu控制将正常自动为您创建MenuItem对象时,它是绑定到POCO集合,使用ItemsSource属性。

但是,此默认行为可以被覆盖!以下是如何...

解决方案

首先,你必须创建一个从ItemContainerTemplateSelector派生的类。或者使用简单的类我创建:

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

其次,你必须向MenuItemContainerTemplateSelector类的引用添加到您的Windows resources对象,像这样:

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

第三,必须设置两个属性(UsesItemContainerTemplateItemContainerTemplateSelector)在MenuMenuItem(在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按预期工作。

快乐编码!

1

没有TemplateSelector A液:

提供ItemContainerTemplates代替的DataTemplates:

<ContextMenu ItemsSource="{Binding Path=MenuItems}" UsesItemContainerTemplate="True"> 
       <ContextMenu.Resources> 
       <ResourceDictionary> 
        <ItemContainerTemplate DataType="{x:Type ViewModel:MenuItemViewModel }"> 
        <MenuItem Header="{Binding Path=Header}" Command="{Binding Path=Command}" UsesItemContainerTemplate="True"> 
         <MenuItem.Icon> 
         <Image Source="{Binding Path=ImageSource}"/> 
         </MenuItem.Icon> 
        </MenuItem> 
        </ItemContainerTemplate> 
        <ItemContainerTemplate DataType="{x:Type ViewModel:SeparatorViewModel}"> 
        <Separator > 
         <Separator.Style> 
         <Style TargetType="{x:Type Separator}" BasedOn="{StaticResource ResourceKey={x:Static MenuItem.SeparatorStyleKey}}"/> 
         </Separator.Style> 
        </Separator> 
        </ItemContainerTemplate> 
       </ResourceDictionary> 
       </ContextMenu.Resources> 
      </ContextMenu> 

注:

  • 我还没有试过儿童
  • 分隔styled wrong:我必须手动重新应用样式
相关问题