在 DropDownButton 中组织项目? [英] Organize Items in DropDownButton?

查看:19
本文介绍了在 DropDownButton 中组织项目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 ObservableCollection 中有一个项目集合,每个项目都有一个特定的国家名称(这只是一个字符串).这是我的收藏:

I've a collection of items inside an ObservableCollection, each item have a specific nation name (that's only a string). This is my collection:

private ObservableCollection<League> _leagues = new ObservableCollection<League>();
    public ObservableCollection<League> Leagues
    {
        get
        {
            return _leagues;
        }
        set
        {
            _leagues = value;
            OnPropertyChanged();
        }
    }

League 模型只有一个 Name 和一个 NationName 属性.Xaml 看起来像这样:

the League model have only a Name and a NationName properties. The Xaml looks like this:

<Controls:DropDownButton Content="Leagues" x:Name="LeagueMenu"
                             ItemsSource="{Binding Leagues}"
                                     ItemTemplate="{StaticResource CombinedTemplate}" >
        <Controls:DropDownButton.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding NationName}" />
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
            </GroupStyle>
        </Controls:DropDownButton.GroupStyle>
</Controls:DropDownButton>

但是我没有得到 NationName 属性的任何标题,DropDown 中的项目没有标题而是作为列表组织,因此没有组织.我正在尝试获得这种倾向.

but I doesn't get any header for the NationName property, the items inside the DropDown are organized without header but as list, so without organization. I'm trying to get this predisposition.

我做错了什么?

推荐答案

Preliminaries

在 WPF(DropDownButton 派生自)的 ItemsControl 中对项目进行分组相当简单,分两步完成.首先,您需要通过调整与源集合关联的 ICollectionView 来设置项目源.然后,您需要使用至少一个 GroupStyle 项目填充 ItemsControl.GroupStyle 集合 - 否则这些项目将以普通(非分组)方式呈现.

Preliminaries

Grouping items in an ItemsControl in WPF (which DropDownButton derives from) is fairly simple, and is accomplished in two steps. First you need to set up the items source by tweaking an ICollectionView associated with the source collection. Then you need to populate the ItemsControl.GroupStyle collection with at least one GroupStyle item - otherwise the items are presented in a plain (non-grouped) manner.

您面临的主要问题是让下拉菜单以分组方式显示项目.不幸的是,与设置项目源不同,在 DropDownButton 控件的情况下,这不是一件容易完成的事情.其原因源于控件(或更准确地说,其模板)的设计方式 - 下拉列表显示在附加到 ButtonContextMenu 中,其中是模板的一部分(参见 MahApps.Metro 源代码).现在ContextMenu 也继承自ItemsControl,它的大部分属性都绑定到模板化的DropDownButton 的对应属性上.然而,它的 GroupStyle 属性不是这种情况,因为它是一个只读的非依赖属性,不能绑定或事件样式.这意味着即使您将项目添加到 DropDownButton.GroupStyle 集合,ContextMenu.GroupStyle 集合仍为空,因此项目以非分组方式呈现.

The main issue you're facing is getting the drop-down to present the items in a grouped manner. Unfortunately, unlike setting up the items source, it is not something that is easily accomplished in case of the DropDownButton control. The reason for that stems from the way the control (or, more precisely, its template) is designed - the drop-down is presented inside a ContextMenu attached to a Button which is part of the template (see MahApps.Metro source code). Now ContextMenu also derives from ItemsControl, and most of its properties are bound to corresponding properties of the templated DropDownButton. That is however not the case for its GroupStyle property, because it's a read-only non-dependency property, and cannot be bound or event styled. That means that even if you add items to DropDownButton.GroupStyle collection, the ContextMenu.GroupStyle collection remains empty, hence the items are presented in non-grouped manner.

最可靠但最麻烦的解决方案是重新模板化控件并将GroupStyle 项直接添加到ContextMenu.GroupStyle 集合.但我可以为您提供一个更简洁的解决方法.

The most reliable, yet most cumbersome solution would be to re-template the control and add GroupStyle items directly to the ContextMenu.GroupStyle collection. But I can offer you a much more concise workaround.

首先,让我们处理第一步 - 设置项目源.最简单的方法(在我看来)是在 XAML 中使用 CollectionViewSource.在你的情况下,它会归结为以下几点:

First of all, let's deal with the first step - setting up the items source. The easiest way (in my opinion) is to use CollectionViewSource in XAML. In your case it would boil down to something along these lines:

<mah:DropDownButton>
    <mah:DropDownButton.Resources>
        <CollectionViewSource x:Key="LeaguesViewSource" Source="{Binding Leagues}">
            <CollectionViewSource.GroupDescriptions>
                <PropertyGroupDescription PropertyName="NationName" />
            </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
    </mah:DropDownButton.Resources>
    <mah:DropDownButton.ItemsSource>
        <Binding Source="{StaticResource LeaguesViewSource}" />
    </mah:DropDownButton.ItemsSource>
</mah:DropDownButton>

现在是主要部分 - 我们的想法是我们将创建一个辅助类,该类将包含一个附加的依赖属性,该属性会将所有者 DropDownButton 控件分配给 ContextMenu 负责展示其项目.更改所有者后,我们将观察其 DropDownButton.GroupStyle 集合并使用 ContextMenu.GroupStyleSelectorContextMenu 提供来自其所有者集合的项目.代码如下:

Now for the main part - the idea is that we'll create a helper class that will contain one attached dependency property that will assign an owner DropDownButton control to the ContextMenu responsible for presenting its items. Upon changing the owner we'll observe its DropDownButton.GroupStyle collection and use ContextMenu.GroupStyleSelector to feed the ContextMenu with items coming from its owner's collection. Here's the code:

public static class DropDownButtonHelper
{
    public static readonly DependencyProperty OwnerProperty =
        DependencyProperty.RegisterAttached("Owner", typeof(DropDownButton), typeof(DropDownButtonHelper), new PropertyMetadata(OwnerChanged));

    public static DropDownButton GetOwner(ContextMenu menu)
    {
        return (DropDownButton)menu.GetValue(OwnerProperty);
    }

    public static void SetOwner(ContextMenu menu, DropDownButton value)
    {
        menu.SetValue(OwnerProperty, value);
    }

    private static void OwnerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var menu = (ContextMenu)d;
        if (e.OldValue != null)
            //unsubscribe from the old owner
            ((DropDownButton)e.OldValue).GroupStyle.CollectionChanged -= menu.OwnerGroupStyleChanged;
        if (e.NewValue != null)
        {
            var button = (DropDownButton)e.NewValue;
            //subscribe to new owner
            button.GroupStyle.CollectionChanged += menu.OwnerGroupStyleChanged;
            menu.GroupStyleSelector = button.SelectGroupStyle;
        }
        else
            menu.GroupStyleSelector = null;
    }

    private static void OwnerGroupStyleChanged(this ContextMenu menu, object sender, NotifyCollectionChangedEventArgs e)
    {
        //this method is invoked whenever owners GroupStyle collection is modified,
        //so we need to update the GroupStyleSelector
        menu.GroupStyleSelector = GetOwner(menu).SelectGroupStyle;
    }

    private static GroupStyle SelectGroupStyle(this DropDownButton button, CollectionViewGroup group, int level)
    {
        //we select a proper GroupStyle from the owner's GroupStyle collection
        var index = Math.Min(level, button.GroupStyle.Count - 1);
        return button.GroupStyle.Any() ? button.GroupStyle[index] : null;
    }
}

为了完成第二步,我们需要为 ContextMenu 绑定 Owner 属性(我们将使用 DropDownButton.MenuStyle这样做)并将一些 GroupStyle 项添加到 DropDownButton:

In order to complete the second step we need to bind the Owner property for the ContextMenu (we'll use DropDownButton.MenuStyle to do that) and add some GroupStyle items to the DropDownButton:

<mah:DropDownButton>
    <mah:DropDownButton.MenuStyle>
        <Style TargetType="ContextMenu" BasedOn="{StaticResource {x:Type ContextMenu}}">
            <Setter Property="local:DropDownButtonHelper.Owner" Value="{Binding RelativeSource={RelativeSource TemplatedParent}}" />
        </Style>
    </mah:DropDownButton.MenuStyle>
    <mah:DropDownButton.GroupStyle>
        <GroupStyle />
    </mah:DropDownButton.GroupStyle>
</mah:DropDownButton>

我认为这应该足以实现您的目标.

This I think should be enough to achieve your goal.

这篇关于在 DropDownButton 中组织项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆