我正在使用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:
<ContextMenu x:Name="contextMenu" ItemsSource="{Binding Path=(local:AbstractSolutionItem.ContextMenu)}"
IsEnabled="{Binding Path=(local:AbstractSolutionItem.ContextMenuEnabled)}"
ItemContainerStyle="{StaticResource contextMenuStyle}"/>
菜单中的每个项目都绑定到IMenuItem对象(菜单项的ViewModel)。单击菜单项时,它使用命令在基础对象上执行命令。这一切都很有效。
但是,一旦命令在IMenuItem类上执行,它有时需要获取用户右键单击的对象的引用以显示上下文菜单(或至少该对象的ViewModel)。这就是 context 菜单的重点。我应该如何将树项ViewModel的引用传递给MenuItem ViewModel?请注意,某些上下文菜单由树中的许多对象共享。
答案 0 :(得分:11)
ContextMenu对象上有一个名为“PlacementTarget”的DP - 它将被设置为上下文菜单所附加的UI元素 - 您甚至可以将其用作绑定源,因此您可以将其传递给您的Command CommandParameter:
http://msdn.microsoft.com/en-us/library/system.windows.controls.contextmenu.placementtarget.aspx
编辑:在您的情况下,您需要PlacementTarget的VM,因此您的绑定可能看起来更像:
{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}
答案 1 :(得分:4)
我通过在父控件(在View中拥有ContextMenu的控件)上处理ContextMenuOpening事件来解决这个问题。我还向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的事实。