簡體   English   中英

使用MVVM,ContextMenu ViewModel如何找到打開ContextMenu的ViewModel?

[英]Using MVVM, how can a ContextMenu ViewModel find the ViewModel that opened the ContextMenu?

我正在使用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);

綁定到基類(以及所有派生類)的View實現了綁定到該屬性的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? 請注意,某些上下文菜單由樹中的許多對象共享。

ContextMenu對象上有一個名為“PlacementTarget”的DP - 它將被設置為上下文菜單所附加的UI元素 - 您甚至可以將其用作綁定源,因此您可以通過CommandParameter將其傳遞給Command:

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

編輯:在您的情況下,您需要PlacementTarget的VM,因此您的綁定可能看起來更像:

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

我通過在父控件(在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這一事實。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM