如何将 Ribbon 控件绑定到我的 ViewModel?

发布于 2024-12-01 11:19:13 字数 3828 浏览 7 评论 0原文

从昨天开始,我一直在努力使用 MVVM 在 WPF 上构建一个(我认为的)简单的功能区。 我在互联网上(以及 Stack Overflow 上)找到了很多链接,但没有一个能够真正解决我的问题。

简而言之,我的问题是:我做错了吗,还是像我一样将功能区绑定到 ViewModel 根本不可能?

详细信息:

这是我的菜单模型:每个MenuGroup应呈现为RibbonGroup,并且MenuGroup包含应呈现为MenuItem的集合RibbonButton(当然在它们各自的RibbonGroup内)。

using Caliburn.Micro;

namespace MyCompany.Poc.Wpf.Models
{
    public class MenuGroup
    {
        public MenuGroup()
        {
            Items = new BindableCollection<MenuItem>();
        }

        public string Name { get; set; }

        public IObservableCollection<MenuItem> Items { get; set; }
    }
}


using System.Windows.Input;

namespace MyCompany.Poc.Wpf.Models
{
    public class MenuItem
    {
        public MenuGroup Group { get; set; }

        public string Name { get; set; }

        public string Link { get; set; }

        public ICommand OpenMenuUrl { get; set; }
    }
}

我的 ViewModel 仅包含这些 MenuGroup 的集合,用于 XAML 上的绑定:

public IObservableCollection<MenuGroup> LegacyMenuItems
{
    get { return _legacyMenuItems; }
}

一旦虚拟机实例化,就会使用假数据填充该集合(暂时):

var group1 = new MenuGroup();
group1.Name = "Group 1";
var group2 = new MenuGroup();
group2.Name = "Group 2";

group1.Items.Add(new MenuItem {Group = group1, Link = "http://www.google.co.uk", Name = "Link 1", OpenMenuUrl = OpenMenuUrl});
group1.Items.Add(new MenuItem {Group = group1, Link = "http://www.google.co.uk", Name = "Link 2", OpenMenuUrl = OpenMenuUrl});
group2.Items.Add(new MenuItem {Group = group2, Link = "http://www.google.co.uk", Name = "Link 3", OpenMenuUrl = OpenMenuUrl});
group2.Items.Add(new MenuItem {Group = group2, Link = "http://www.google.co.uk", Name = "Link 4", OpenMenuUrl = OpenMenuUrl});

LegacyMenuItems.Add(group1);
LegacyMenuItems.Add(group2);

现在是 XAML:

<my:Ribbon  DockPanel.Dock="Top">
    <my:RibbonTab Header="Legacy A.I." ItemsSource="{Binding LegacyMenuItems}">
        <my:RibbonTab.ItemTemplate>
            <DataTemplate>
                <my:RibbonGroup Header="{Binding Name}" ItemsSource="{Binding Items}">
                    <my:RibbonGroup.ItemTemplate>
                        <DataTemplate>
                            <my:RibbonButton Label="{Binding Name}" Command="{Binding OpenMenuUrl}" CommandParameter="{Binding Link}"></my:RibbonButton>
                        </DataTemplate>
                    </my:RibbonGroup.ItemTemplate>
                </my:RibbonGroup>
            </DataTemplate>
        </my:RibbonTab.ItemTemplate>
    </my:RibbonTab>

    <my:RibbonTab Header="Static">
        <my:RibbonGroup Name="Administration" Header="Admin">
            <my:RibbonButton Label="Stuffs" Command="{Binding Path=OpenMenuUrl}" CommandParameter="http://www.mycompany.com/somelink"></my:RibbonButton>
            <my:RibbonButton Label="Google" Command="{Binding Path=OpenMenuUrl}" CommandParameter="http://www.google.co.uk"></my:RibbonButton>
        </my:RibbonGroup>
    </my:RibbonTab>

</my:Ribbon>

以及它呈现的内容: 看起来不太对,是吗... 静态加载,工作起来就像一个魅力...

如您所见,“静态”选项卡运行良好,“标题”功能区组(“管理员”)的“显示在正确的位置。

现在,“Legacy AI”选项卡没有按钮(每组中应该有 2 个按钮),并且 RibbonGroup 标题显示得很有趣(低于应有的位置 )。

如果您对我在这里做错了什么有任何线索,请告诉我:) 我对 WPF 世界非常陌生,所以我显然不能正确理解模板......

一些事实可以帮助您拨打电话: - 模型已正确加载,因为我们可以看到“Group 1”和“Group 2”,它们是 ViewModel 中加载的虚假数据的一部分 - 我尝试了 Telerik 的 RadRibbon,它的行为完全一样!因此,除非他们在同一个地方都错了,否则问题一定来自我,

晚安,祝你好运:)

I've been struggling since yesterday to build a (what I thought) simple Ribbon on WPF, using MVVM.
I found quite a few links on the internet (and on Stack Overflow), but none could really solve my problem.

In a nutshell my question is: Am I doing it wrong, or is it just plain impossible to bind a Ribbon to a ViewModel like I'm doing?

In Details:

This is my model for the menu: Each MenuGroup should be rendered as a RibbonGroup, and MenuGroup contains a collection of MenuItem which should be rendered as a RibbonButton (inside their respective RibbonGroup of course).

using Caliburn.Micro;

namespace MyCompany.Poc.Wpf.Models
{
    public class MenuGroup
    {
        public MenuGroup()
        {
            Items = new BindableCollection<MenuItem>();
        }

        public string Name { get; set; }

        public IObservableCollection<MenuItem> Items { get; set; }
    }
}


using System.Windows.Input;

namespace MyCompany.Poc.Wpf.Models
{
    public class MenuItem
    {
        public MenuGroup Group { get; set; }

        public string Name { get; set; }

        public string Link { get; set; }

        public ICommand OpenMenuUrl { get; set; }
    }
}

My ViewModel just contains a collection of those MenuGroup, for the binding on the XAML:

public IObservableCollection<MenuGroup> LegacyMenuItems
{
    get { return _legacyMenuItems; }
}

The collection is populated (for the time being) as soon as the VM is instanciated, with fake data):

var group1 = new MenuGroup();
group1.Name = "Group 1";
var group2 = new MenuGroup();
group2.Name = "Group 2";

group1.Items.Add(new MenuItem {Group = group1, Link = "http://www.google.co.uk", Name = "Link 1", OpenMenuUrl = OpenMenuUrl});
group1.Items.Add(new MenuItem {Group = group1, Link = "http://www.google.co.uk", Name = "Link 2", OpenMenuUrl = OpenMenuUrl});
group2.Items.Add(new MenuItem {Group = group2, Link = "http://www.google.co.uk", Name = "Link 3", OpenMenuUrl = OpenMenuUrl});
group2.Items.Add(new MenuItem {Group = group2, Link = "http://www.google.co.uk", Name = "Link 4", OpenMenuUrl = OpenMenuUrl});

LegacyMenuItems.Add(group1);
LegacyMenuItems.Add(group2);

Now the XAML:

<my:Ribbon  DockPanel.Dock="Top">
    <my:RibbonTab Header="Legacy A.I." ItemsSource="{Binding LegacyMenuItems}">
        <my:RibbonTab.ItemTemplate>
            <DataTemplate>
                <my:RibbonGroup Header="{Binding Name}" ItemsSource="{Binding Items}">
                    <my:RibbonGroup.ItemTemplate>
                        <DataTemplate>
                            <my:RibbonButton Label="{Binding Name}" Command="{Binding OpenMenuUrl}" CommandParameter="{Binding Link}"></my:RibbonButton>
                        </DataTemplate>
                    </my:RibbonGroup.ItemTemplate>
                </my:RibbonGroup>
            </DataTemplate>
        </my:RibbonTab.ItemTemplate>
    </my:RibbonTab>

    <my:RibbonTab Header="Static">
        <my:RibbonGroup Name="Administration" Header="Admin">
            <my:RibbonButton Label="Stuffs" Command="{Binding Path=OpenMenuUrl}" CommandParameter="http://www.mycompany.com/somelink"></my:RibbonButton>
            <my:RibbonButton Label="Google" Command="{Binding Path=OpenMenuUrl}" CommandParameter="http://www.google.co.uk"></my:RibbonButton>
        </my:RibbonGroup>
    </my:RibbonTab>

</my:Ribbon>

And what it renders:
Doesn't look right, does it...
Statically loaded, works like a charm...

As you can see, the "Static" tab works well and the "title" for the ribbon group ("Admin") is displayed at the right place.

Now, the "Legacy A.I." tab, has no buttons (there should be 2 buttons in each group), and the RibbonGroup titles are displayed funny (below where they should be).

If you have any clue on what I'm doing wrong here, please tell me :)
I'm very new on the WPF world, so I obviously don't understand templating properly...

A few facts to help you make a call:
- The Model is loaded correctly, since we can see "Group 1" and "Group 2" which are part of the fake data loaded in the ViewModel
- I tried Telerik's RadRibbon and it behaves exactly the same! So unless they are BOTH wrong at the same place, the problem must comes from me

Good night and good luck :)

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

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

发布评论

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

评论(3

陌路终见情 2024-12-08 11:19:13

我还在 MVVM 应用程序中使用功能区,并决定坚持使用 XAML 中定义的控件,将它们链接到视图模型层中定义的类中的静态 ICommand 属性。这是非常不灵活的,但到目前为止对我有用。

如果您已下载并安装了官方 Microsoft Ribbon,您将在以下位置找到它的源代码和一些示例:

C:\Program Files\Microsoft 功能区
WPF\MicrosoftRibbonForWPFSourceAndSamples

这包括一个也实现 MVVM 的示例。这使用了完全不同的方法,虽然可能不是您需要的,但我认为仔细检查可能会有所帮助。

I am using the ribbon also in a MVVM application and decided to stick with controls defined in XAML linking them to static ICommand properties in classes defined in my viewmodel layer. This is very inflexible but works for me so far.

If you have downloaded and installed the official Microsoft Ribbon you will find it's source and some sample's in:

C:\Program Files\Microsoft Ribbon for
WPF\MicrosoftRibbonForWPFSourceAndSamples

This includes a sample that also implements MVVM. This uses a totally different method though an may not be what you need, but I think it may be helpful to look it over.

东风软 2024-12-08 11:19:13

我昨天遇到了同样的问题,并努力寻找解决方案。

我认为您的问题可以通过 HierarchicalDataTemplate 来解决。

<r:Ribbon>
    <r:RibbonTab Header="Legacy A.I." ItemsSource="{Binding LegacyMenuItems}">
        <r:RibbonTab.Style>
            <Style TargetType="{x:Type r:RibbonTab}">
                <Setter Property="ItemsSource" Value="{Binding LegacyMenuItems}" />
                <Setter Property="ItemTemplate">
                    <Setter.Value>
                        <HierarchicalDataTemplate DataType      = "{x:Type r:RibbonGroup}"
                                                  ItemsSource   = "{Binding Items}" >
                            <TextBlock Text="{Binding Name}" />
                        </HierarchicalDataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </r:RibbonTab.Style>
    </r:RibbonTab>
</r:Ribbon>

I had the same problem yesterday and struggled a lot to find a solution.

I think your problem could be solved with a HierarchicalDataTemplate.

<r:Ribbon>
    <r:RibbonTab Header="Legacy A.I." ItemsSource="{Binding LegacyMenuItems}">
        <r:RibbonTab.Style>
            <Style TargetType="{x:Type r:RibbonTab}">
                <Setter Property="ItemsSource" Value="{Binding LegacyMenuItems}" />
                <Setter Property="ItemTemplate">
                    <Setter.Value>
                        <HierarchicalDataTemplate DataType      = "{x:Type r:RibbonGroup}"
                                                  ItemsSource   = "{Binding Items}" >
                            <TextBlock Text="{Binding Name}" />
                        </HierarchicalDataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </r:RibbonTab.Style>
    </r:RibbonTab>
</r:Ribbon>
梦开始←不甜 2024-12-08 11:19:13

Captain Necroposter 在这里:

我遇到了相同的渲染问题,这是我的解决方案

            <HierarchicalDataTemplate DataType="{x:Type navigation:RibbonTabViewModel}" ItemsSource="{Binding Path=Groups}">
                <TextBlock Text="{Binding Path=Title}"></TextBlock>
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type navigation:RibbonGroupViewModel}" ItemsSource="{Binding Path=Items}">
                <TextBlock Text="{Binding Path=Title}" ></TextBlock>
            </HierarchicalDataTemplate>
            <DataTemplate DataType="{x:Type navigation:RibbonButtonViewModel}">
                <RibbonButton Label="{Binding Path=Title}" Command="{Binding Path=ClickedCommand}" CommandParameter="{Binding Path=.}"></RibbonButton>
            </DataTemplate>

首先,我有一个 RibbonGroup 作为 RibbonGroupViewModel 的模板内容。感谢最新的 VS,我能够检查活动树并找到那里的问题。

Captain Necroposter here:

I had the same rendering issue and this is my solution

            <HierarchicalDataTemplate DataType="{x:Type navigation:RibbonTabViewModel}" ItemsSource="{Binding Path=Groups}">
                <TextBlock Text="{Binding Path=Title}"></TextBlock>
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type navigation:RibbonGroupViewModel}" ItemsSource="{Binding Path=Items}">
                <TextBlock Text="{Binding Path=Title}" ></TextBlock>
            </HierarchicalDataTemplate>
            <DataTemplate DataType="{x:Type navigation:RibbonButtonViewModel}">
                <RibbonButton Label="{Binding Path=Title}" Command="{Binding Path=ClickedCommand}" CommandParameter="{Binding Path=.}"></RibbonButton>
            </DataTemplate>

To begin with i had a RibbonGroup as template content for my RibbonGroupViewModel. Thanks to latest VS i was able to inspect the live tree and find the issue there.

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