Используя MVVM, как ContextMenu ViewModel может найти ViewModel, который открыл ContextMenu?

Я использую MVVM для привязки представлений с объектами в Дереве. У меня есть базовый класс, который реализует объекты в моем дереве, и что базовый класс имеет свойство ContextMenu:

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

Представление, которое связывает с базовым классом (и все производные классы) реализует ContextMenu, который связывает с тем свойством:


Каждый объект в меню связывается с объектом IMenuItem (ViewModel для пунктов меню). При нажатии на пункт меню он использует Команды для выполнения команды на базовом объекте. Это все работает отлично.

Однако, после того как команда выполняется на классе IMenuItem, это иногда должно получать ссылку на объект, по которому щелкнул правой кнопкой пользователь поднять контекстное меню (или ViewModel того объекта, по крайней мере). Это - смысл контекстного меню. Как я должен пойти о передаче ссылки элемента дерева ViewModel к MenuItem ViewModel? Обратите внимание, что некоторые контекстные меню совместно используются многими объектами в дереве.

8
задан Scott Whitlock 30 March 2011 в 13:19
поделиться

2 ответа

Я решил эту проблему, обработав событие ContextMenuOpening в родительском элементе управления (тот, который владел ContextMenu в представлении). Я также добавил свойство Context в 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;
        }
    }

Это использует тот факт, что одновременно может быть открыто только одно ContextMenu.

4
ответ дан 5 December 2019 в 11:24
поделиться

В объекте ContextMenu есть DP под названием "PlacementTarget" - он будет установлен на элемент пользовательского интерфейса, к которому прикреплено контекстное меню - вы даже можете использовать его в качестве источника привязки, чтобы передать его вашей команде через CommandParameter:

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

edit: в вашем случае вам нужен VM объекта PlacementTarget, поэтому ваша привязка, вероятно, будет выглядеть так:

{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}
11
ответ дан 5 December 2019 в 11:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: