C# 使用MVVM,ContextMenu ViewModel如何找到打开ContextMenu的ViewModel?

C# 使用MVVM,ContextMenu ViewModel如何找到打开ContextMenu的ViewModel?,c#,wpf,mvvm,contextmenu,C#,Wpf,Mvvm,Contextmenu,我正在使用MVVM将视图绑定到树中的对象。我有一个实现树中项目的基类,该基类有一个ContextMenu属性: public IEnumerable<IMenuItem> ContextMenu { get { return m_ContextMenu; } protected set { if (m_ContextMenu != value

我正在使用MVVM将视图绑定到树中的对象。我有一个实现树中项目的基类,该基类有一个ContextMenu属性:

    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}"/>
public IEnumerable上下文菜单
{
得到
{
返回m_上下文菜单;
}
保护集
{
if(m_ContextMenu!=值)
{
m_ContextMenu=值;
NotifyPropertyChanged(m_上下文菜单);
}
}
}
private IEnumerable m_ContextMenu=null;
静态只读属性ChangedEventArgs m_ContextMenuArgs=
NotifyPropertyChangedHelper.CreateArgs对象(菜单项的视图模型)。单击菜单项时,它使用命令在基础对象上执行命令。这一切都很好


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

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

    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;
        }
    }
private void stackPanel\u contextmenu打开(
对象发送方,ContextMenuEventArgs(e)
{
StackPanel sp=发送方作为StackPanel;
如果(sp!=null)
{
//solutionItem是“上下文”
ISolutionItem解决方案Item=
sp.DataContext作为ISolutionItem;
如果(solutionItem!=null)
{
IEnumerable items=
solutionItem.ContextMenu为IEnumerable;
如果(项!=null)
{
foreach(项目中的IMenuItem项目)
{
//将自动设置所有
//子菜单项的上下文也是如此
item.Context=solutionItem;
}
}
其他的
{
e、 已处理=正确;
}
}
其他的
{
e、 已处理=正确;
}
}
其他的
{
e、 已处理=正确;
}
}

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

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

编辑:在您的情况下,您需要PlacementTarget的VM,因此您的绑定可能更像:

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

-如果使用RelativeSource,则无法指定1个源。运行时异常.DataContext=“{Binding PlacementTarget.DataContext,RelativeSource={RelativeSource Self}”