2010-02-21 41 views
2

我有一个视图模型(AbstractContextMenu)代表我的上下文菜单(IContextMenu),我绑定一个真正的文本菜单将其与一个DataTemplate:我可以使用DataTemplate将ContextMenu应用于ContextMenuViewModel吗?

<DataTemplate DataType="{x:Type local:AbstractContextMenu}"> 
    <ContextMenu x:Name="contextMenu" 
      ItemsSource="{Binding Path=(local:IContextMenu.Items)}" 
      IsEnabled="{Binding Path=(local:IContextMenu.IsEnabled)}"/> 
</DataTemplate> 

然后,我有一个虚拟ConcreteContextMenu进行测试,只是从AbstractContextMenu继承。 AbstractContextMenu只是实现了这个接口:

public interface IContextMenu : IExtension 
{ 
    IEnumerable<IMenuItem> Items { get; set; } 
    bool IsEnabled { get; set; } 
} 

我用它作为其他视图模型对象的属性:

public IContextMenu ContextMenu 
    { 
     get 
     { 
      return m_ContextMenu; 
     } 
     protected set 
     { 
      if (m_ContextMenu != value) 
      { 
       m_ContextMenu = value; 
       NotifyPropertyChanged(m_ContextMenuArgs); 
      } 
     } 
    } 
    private IContextMenu m_ContextMenu = new ConcreteContextMenu(); 
    static readonly PropertyChangedEventArgs m_ContextMenuArgs = 
     NotifyPropertyChangedHelper.CreateArgs<AbstractSolutionItem>(o => o.ContextMenu); 

然后我绑定一个StackPanel到视图模型,并在StackPanel中ContextMenu属性绑定到视图模型的ContextMenu属性:

<StackPanel Orientation="Horizontal" 
       ContextMenu="{Binding Path=(local:AbstractSolutionItem.ContextMenu)}" 
       ContextMenuOpening="stackPanel_ContextMenuOpening"> 
    <!-- stuff goes in here --> 
    </StackPanel> 

当我运行此,上的StackPanel中的ContextMenuOpening事件被激发,但文本菜单是NE显示。我不确定我是否可以执行此操作(使用DataTemplate将ContextMenu应用于ContextMenu ViewModel)。有人知道吗?

回答

1

AbstractSolutionItem.ContextMenu是什么类型的?如果它对应于您的问题中的ContextMenu属性,那么问题可能是该类型错误。 FrameworkElementContextMenu财产预计实际ContextMenu,而不是IContextMenu。尝试在调试应用程序时检查输出窗口 - 您可能会收到错误消息,指出这是问题所在。

而不是使用DataTemplate来定义ContextMenu的,只是把模板StackPanel.ContextMenu的内容:

<StackPanel Orientation="Horizontal" 
    ContextMenu="{Binding Path=(local:AbstractSolutionItem.ContextMenu)}" 
    ContextMenuOpening="stackPanel_ContextMenuOpening"> 
    <StackPanel.ContextMenu DataContext="{Binding Path=(local:AbstractSolutionItem.ContextMenu)}"> 
     <ContextMenu x:Name="contextMenu" 
      ItemsSource="{Binding Path=Items}" 
      IsEnabled="{Binding Path=IsEnabled}"/> 
    </StackPanel.ContextMenu> 
    <!-- stuff goes in here --> 
</StackPanel> 

这应该让你最的方式存在。但是,由于ContextMenu不知道如何从IMenuItem创建MenuItem,所以仍然存在问题。要解决这个问题,请为ContextMenu创建一个ItemTemplate,它将IMenuItem的成员绑定到`MenuItem。

+0

嗨安迪。 WPF可以识别我为AbstractMenuItem定义的DataTemplate,它确实创建了菜单(毕竟是MVVM的核心),但正如你所说,似乎我不能将StackPanel.ContextMenu属性绑定到一个随机对象并让WPF将我的DataTemplate应用到它。我希望有办法解决这个问题,但看起来我的选择是零。谢谢。太糟糕了 - 我试图去完整的MVVM,但很难。 – 2010-02-27 04:30:41

+0

这并没有真正解决我的问题,但由于看起来没有解决方案,我想要做什么,这是“正确的”。 ;) – 2010-02-28 13:47:54

0

您能否在DataTemplate中的ItemsSource属性中使用语法?使用括号通常意味着附属的财产。并且Items似乎不是由IContextMenu定义的附加属性(因为接口不能定义这样的属性)。

DataTemplate链接到类型为AbstractContextMenu的对象,该对象具有名为Items的属性。因此,DataTemplate中可以简单地引用这样的:

<DataTemplate DataType="{x:Type local:AbstractContextMenu}"> 
    <ContextMenu x:Name="contextMenu" 
      ItemsSource="{Binding Path=Items)}" 
      IsEnabled="{Binding Path=IsEnabled}"/> 
</DataTemplate> 

如果AbstractSolutionItem类是StackPanel的虚拟机,你可以结合这样的:

<StackPanel Orientation="Horizontal" 
      ContextMenu="{Binding Path=ContextMenu}" 
      ContextMenuOpening="stackPanel_ContextMenuOpening"> 
<!-- stuff goes in here --> 
</StackPanel> 

当然,DataTemplate中必须来自StackPanel的“可访问”。

+0

您可能不熟悉这种绑定语法,但它与您所描述的完全相同,只是效率更高,因为它可以在编译时而不是运行时解析。我忘记了语法的名称,但是我尽可能地将其转换为使用它,因为使用MVVM,您会执行大量绑定和性能问题。 – 2010-02-28 02:23:44

0

将视图的ContextMenu属性(本场景中的StackPanel)绑定到ViewModel的ContextMenu属性,并为绑定提供一个IValueConverter,它将创建ContextMenu对象并将IContextMenu设置为它的DataContext。