我可以使用DataTemplate将ContextMenu应用于ContextMenuViewModel吗?

时间:2010-02-21 22:10:48

标签: wpf mvvm datatemplate contextmenu

我有一个表示我的上下文菜单(IContextMenu)的ViewModel(AbstractContextMenu),我使用DataTemplate将一个真实的ContextMenu绑定到它:

<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并将StackPanel上的ContextMenu属性绑定到ViewModel的ContextMenu属性:

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

当我运行它时,会触发StackPanel上的ContextMenuOpening事件,但不会显示ContextMenu。我不确定我是否可以这样做(使用DataTemplate将ContextMenu应用于ContextMenu ViewModel)。有人知道吗?

3 个答案:

答案 0 :(得分:1)

AbstractSolutionItem.ContextMenu的类型是什么?如果它对应于您问题中的ContextMenu属性,则问题可能是类型错误。 ContextMenu的{​​{1}}属性预计会有FrameworkElement,而不是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的成员绑定到“MenuItem”。

答案 1 :(得分:0)

您是否可以了解ItemsSourceDataTemplate属性中使用的语法?使用括号通常表示附加属性。并且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的VM,您可以像这样绑定它:

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

当然,DataTemplate必须从StackPanel“可访问”。

答案 2 :(得分:0)

将视图的ContextMenu属性(本场景中的StackPanel)绑定到ViewModel的ContextMenu属性,并为绑定提供IValueConverter,该绑定将创建ContextMenu对象并将IContextMenu设置为它的DataContext。