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

发布于 2024-08-22 08:29:36 字数 1820 浏览 5 评论 0原文

我有一个代表我的上下文菜单 (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>

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

I have a ViewModel (AbstractContextMenu) that represents my context menu (IContextMenu), and I bind a real ContextMenu to it with a DataTemplate:

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

Then I have a dummy ConcreteContextMenu for testing that just inherits from AbstractContextMenu. AbstractContextMenu just implements this interface:

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

I'm using it as a property of another ViewModel object:

    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);

Then I bind a StackPanel to that ViewModel and bind the ContextMenu property on the StackPanel to the ContextMenu property of the ViewModel:

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

When I run this, the ContextMenuOpening event on the StackPanel is fired, but the ContextMenu is never displayed. I'm not sure if I can even do this (apply a ContextMenu to a ContextMenu ViewModel using a DataTemplate). Anyone know?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

等数载,海棠开 2024-08-29 08:29:36

AbstractSolutionItem.ContextMenu 的类型是什么?如果它对应于您问题中的 ContextMenu 属性,则问题可能是类型错误。 FrameworkElementContextMenu 属性需要一个实际的 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 不知道如何从 IMenuItem 创建 MenuItem。要解决此问题,请为 ContextMenu 创建一个 ItemTemplate,它将 IMenuItem 的成员绑定到 `MenuItem。

What is the type of AbstractSolutionItem.ContextMenu? If it corresponds to the ContextMenu property in your question, then the problem could be that the type is wrong. The ContextMenu property of FrameworkElement is expecting an actual ContextMenu, not an IContextMenu. Try checking the output window while debugging your app - you might get an error message stating that this is the problem.

Instead of using a DataTemplate to define your ContextMenu, just put the contents of the template 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>

That should get you most of the way there. However, there is still a problem since the ContextMenu does not know how to create a MenuItem from an IMenuItem. To solve this, create an ItemTemplate for the ContextMenu, which binds members of IMenuItem to `MenuItem.

南七夏 2024-08-29 08:29:36

您能否介绍一下 DataTemplate 中的 ItemsSource 属性中使用的语法?使用括号通常意味着附加属性。并且 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 中“可访问”。

Could you shed some light on the syntax used in the ItemsSource property in the DataTemplate ? Using parentheses usually means an attached property. And Items does not seem to be an attached property defined by IContextMenu (as an interface cannot define such a property).

The DataTemplate is linked to an object of type AbstractContextMenu which has a property called Items. So, the DataTemplate could simply reference it like this:

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

If the AbstractSolutionItem class is the VM of the StackPanel, you could bind it like this:

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

Of course, the DataTemplate must be "accessible" from the StackPanel.

记忆里有你的影子 2024-08-29 08:29:36

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

Bind the ContextMenu property of your view (StackPanel in this scenario) to the ContextMenu property of your ViewModel and provide a IValueConverter to the binding that will create the ContextMenu object and set the IContextMenu to it's DataContext.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文