2010-02-21 3 views
2

У меня есть ViewModel (AbstractContextMenu), который представляет мое контекстное меню (IContextMenu), и я связываю реальный ContextMenu к нему с DataTemplate:Могу ли я применить ContextMenu к ContextMenuViewModel с помощью DataTemplate?

<DataTemplate DataType="{x:Type local:AbstractContextMenu}"> 
    <ContextMenu x:Name="contextMenu" 
      ItemsSource="{Binding Path=(local:IContextMenu.Items)}" 
      IsEnabled="{Binding Path=(local:IContextMenu.IsEnabled)}"/> 
</DataTemplate> 

Тогда у меня есть фиктивный ConcreteContextMenu для тестирования, которые просто наследуется от AbstractContextMenu , AbstractContextMenu просто реализует этот интерфейс:

public interface IContextMenu : IExtension 
{ 
    IEnumerable<IMenuItem> Items { get; set; } 
    bool IsEnabled { get; set; } 
} 

Я использую его как свойство другого объекта ViewModel:

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

Затем я связать с StackPanel к этому ViewModel и связать свойство ContextMenu на StackPanel в свойство ContextMenu из ViewModel:

<StackPanel Orientation="Horizontal" 
       ContextMenu="{Binding Path=(local:AbstractSolutionItem.ContextMenu)}" 
       ContextMenuOpening="stackPanel_ContextMenuOpening"> 
    <!-- stuff goes in here --> 
    </StackPanel> 

Когда я запускаю это, событие ContextMenuOpening на StackPanel обжигают, но ContextMenu пе ver отображается. Я не уверен, могу ли я это сделать (примените ContextMenu к ContextMenu ViewModel с помощью DataTemplate). Кто-нибудь знает?

ответ

1

Что такое AbstractSolutionItem.ContextMenu? Если это соответствует свойству ContextMenu в вашем вопросе, проблема может заключаться в том, что тип неправильный. Свойство ContextMenuFrameworkElement ожидает фактического ContextMenu, а не IContextMenu. Попробуйте проверить окно вывода при отладке приложения - вы можете получить сообщение об ошибке, в котором говорится, что это проблема.

Вместо того, чтобы использовать DataTemplate определить свой ContextMenu, просто поместить содержимое шаблона StackPanel.ContextMenu:

<StackPanel Orientation="Horizontal" 
    ContextMenu="{Binding Path=(local:AbstractSolutionItem.ContextMenu)}" 
    ContextMenuOpening="stackPanel_ContextMenuOpening"> 
    <StackPanel.ContextMenu DataContext="{Binding Path=(local:AbstractSolutionItem.ContextMenu)}"> 
     <ContextMenu x:Name="contextMenu" 
      ItemsSource="{Binding Path=Items}" 
      IsEnabled="{Binding Path=IsEnabled}"/> 
    </StackPanel.ContextMenu> 
    <!-- stuff goes in here --> 
</StackPanel> 

Что вы должны получить большую часть пути туда. Однако по-прежнему существует проблема, так как ContextMenu не знает, как создать MenuItem от IMenuItem. Чтобы решить эту проблему, создайте ItemTemplate для ContextMenu, который связывает членов IMenuItem с `MenuItem.

+0

Привет Энди. WPF распознает DataTemplate I, определенный для AbstractMenuItem, и он действительно создает меню просто отлично (это в основе MVVM), но, как вы сказали, кажется, я не могу просто привязать свойство StackPanel.ContextMenu к случайному объекту и WPF применит мой DataTemplate к нему. Я надеялся найти способ обойти это, но похоже, что мои варианты ноль. Благодарю. Слишком плохо - я пытаюсь пройти полный MVVM, но это сложно. –

+0

Это действительно не помогло решить мою проблему, но, похоже, что нет решения для того, что я хотел сделать, это «правильный». ;) –

0

Не могли бы вы пролить свет на синтаксис, используемый в объекте ItemsSource в DataTemplate? Использование круглых скобок обычно означает прикрепленное свойство. И Items не является прикрепленным свойством, определяемым IContextMenu (поскольку интерфейс не может определить такое свойство).

DataTemplate связан с объектом типа AbstractContextMenu, который имеет свойство Items. Таким образом, DataTemplate может просто ссылаться на него, как это:

<DataTemplate DataType="{x:Type local:AbstractContextMenu}"> 
    <ContextMenu x:Name="contextMenu" 
      ItemsSource="{Binding Path=Items)}" 
      IsEnabled="{Binding Path=IsEnabled}"/> 
</DataTemplate> 

Если AbstractSolutionItem класс ВМ из StackPanel, вы можете связать это следующим образом:

<StackPanel Orientation="Horizontal" 
      ContextMenu="{Binding Path=ContextMenu}" 
      ContextMenuOpening="stackPanel_ContextMenuOpening"> 
<!-- stuff goes in here --> 
</StackPanel> 

Конечно, DataTemplate должен быть «доступно» из StackPanel.

+0

Возможно, вы не знакомы с этим синтаксисом связывания, но он работает точно так же, как вы описали, только он более эффективен, поскольку его можно решить во время компиляции, а не во время выполнения. Я забыл название синтаксиса, но я решил использовать его там, где это было возможно, потому что с MVVM вы делаете много привязки и производительности. –

0

Привяжите свойство ContextMenu вашего представления (StackPanel в этом сценарии) к свойству ContextMenu вашего ViewModel и предоставите IValueConverter привязку, которая создаст объект ContextMenu, и установите IContextMenu в свой DataContext.

Смежные вопросы