如何将Ribbon控件绑定到ViewModel?

时间:2011-08-25 08:19:45

标签: wpf mvvm viewmodel ribbon caliburn.micro

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

简而言之,我的问题是:我做错了,或者像我正在做的那样将Ribbon绑定到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>

它呈现的内容: Doesn't look right, does it... Statically loaded, works like a charm...

正如您所看到的,“静态”选项卡效果很好,功能区组(“管理员”)的“标题”显示在正确的位置。

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

如果你对我在这里做错了什么线索,请告诉我:) 我是WPF世界的新手,所以我显然不明白正确的模板...

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

晚安,祝你好运:)。

3 个答案:

答案 0 :(得分:1)

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

如果你已经下载并安装了官方的Microsoft功能区,你会发现它的来源和一些样本:

  

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

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

答案 1 :(得分:0)

昨天我遇到了同样的问题,并且很难找到解决方案。

我认为您的问题可以通过 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>

答案 2 :(得分:0)

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我能够检查实时树并找到问题。