2010-02-21 70 views
7

我使用MVVM将视图绑定到树中的对象。我有一个实现在我的树中的项目一个基类和基类有一个ContextMenu属性:使用MVVM,ContextMenu ViewModel如何找到打开ContextMenu的ViewModel?

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

结合基类(和所有派生类)实现了结合到一个文本菜单的查看属性:

<ContextMenu x:Name="contextMenu" ItemsSource="{Binding Path=(local:AbstractSolutionItem.ContextMenu)}" 
      IsEnabled="{Binding Path=(local:AbstractSolutionItem.ContextMenuEnabled)}" 
      ItemContainerStyle="{StaticResource contextMenuStyle}"/> 

在菜单中的每一项被绑定到一个IMenuItem对象(一个ViewModel所述菜单项)。当你点击菜单项时,它使用命令在基础对象上执行命令。这一切都很好。

但是,一旦命令在IMenuItem类上执行,它有时需要获取用户右键单击的对象的引用,以调出上下文菜单(或至少该对象的ViewModel)。这是上下文菜单的整点。我应该如何将树项目ViewModel的引用传递给MenuItem ViewModel?请注意,一些上下文菜单由树中的许多对象共享。

回答

4

我通过处理父控件上的ContextMenuOpening事件(在View中拥有ContextMenu的事件)解决了这个问题。我还向IMenuItem添加了一个Context属性。处理程序如下所示:

private void stackPanel_ContextMenuOpening(
     object sender, ContextMenuEventArgs e) 
    { 
     StackPanel sp = sender as StackPanel; 
     if (sp != null) 
     { 
      // solutionItem is the "context" 
      ISolutionItem solutionItem = 
       sp.DataContext as ISolutionItem; 
      if (solutionItem != null) 
      { 
       IEnumerable<IMenuItem> items = 
        solutionItem.ContextMenu as IEnumerable<IMenuItem>; 
       if (items != null) 
       { 
        foreach (IMenuItem item in items) 
        { 
         // will automatically set all 
         // child menu items' context as well 
         item.Context = solutionItem; 
        } 
       } 
       else 
       { 
        e.Handled = true; 
       } 
      } 
      else 
      { 
       e.Handled = true; 
      } 
     } 
     else 
     { 
      e.Handled = true; 
     } 
    } 

这利用了一次只能打开一个ContextMenu的事实。

10

ContextMenu对象上有一个名为“PlacementTarget”的DP - 将设置为上下文菜单所附带的UI元素 - 您甚至可以将它用作绑定源,因此您可以将它传递给您的命令通过CommandParameter:

http://msdn.microsoft.com/en-us/library/system.windows.controls.contextmenu.placementtarget.aspx

编辑:你的情况,你会希望PlacementTarget的虚拟机,所以你会结合可能看起来更像:

{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}} 
+0

-1来源不能如果指定使用RelativeSource。运行时异常。 – 2012-03-20 18:18:34

+0

DataContext =“{Binding PlacementTarget.DataContext,RelativeSource = {RelativeSource Self}}” – JoanComasFdz 2012-04-17 09:05:54