在下拉按钮中组织项目
本文关键字:项目 按钮 | 更新日期: 2023-09-27 18:12:17
我在ObservableCollection
中有一个项目集合,每个项目都有一个特定的国家名称(这只是一个字符串)。这是我的收藏:
private ObservableCollection<League> _leagues = new ObservableCollection<League>();
public ObservableCollection<League> Leagues
{
get
{
return _leagues;
}
set
{
_leagues = value;
OnPropertyChanged();
}
}
League
模型只有一个Name
和一个NationName
性质。Xaml
看起来像这样:
<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
内部的项目没有头,但作为列表组织,所以没有组织。我正在努力改变这种倾向。
我做错了什么?
预演
在WPF中对ItemsControl
(DropDownButton
派生自WPF)中的项进行分组相当简单,分两步完成。首先,您需要通过调整与源集合关联的ICollectionView
来设置项目源。然后,您需要用至少一个GroupStyle
项目填充ItemsControl.GroupStyle
集合—否则,这些项目将以普通(非分组)的方式显示。
您面临的主要问题是如何使下拉菜单以分组方式显示项目。不幸的是,与设置项目源不同,在DropDownButton
控件的情况下,这不是容易完成的事情。这样做的原因源于控件(或者更准确地说,是它的模板)的设计方式——下拉菜单是在一个ContextMenu
中显示的,Button
是模板的一部分(参见MahApps)。Metro源代码)。现在ContextMenu
也是从ItemsControl
派生出来的,它的大部分属性都绑定到模板化的DropDownButton
的相应属性上。然而,它的GroupStyle
属性不是这种情况,因为它是一个只读的非依赖性属性,不能绑定或事件样式。这意味着即使您将项目添加到DropDownButton.GroupStyle
集合中,ContextMenu.GroupStyle
集合仍然为空,因此项目以非分组方式呈现。
解决方案(解决方案)
最可靠,但最麻烦的解决方案是重新模板控件,并将GroupStyle
项直接添加到ContextMenu.GroupStyle
集合中。但是我可以给你一个更简洁的解决方法。
首先,让我们处理第一步—设置项目源。在我看来,最简单的方法是在XAML中使用CollectionViewSource
。在您的情况下,它可以归结为以下内容:
<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.GroupStyleSelector
向ContextMenu
提供来自其所有者集合的项目。下面是代码:
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
来做到这一点),并向DropDownButton
添加一些GroupStyle
项:
<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>
我认为这应该足以实现你的目标。
如果你查看了你链接到的其他帖子,答案已经包含了一切-特别是你需要绑定到一个CollectionView,而不是直接到集合。然后你可以在CollectionView上设置分组。
所以,在你的例子中,定义属性:public ICollectionView LeaguesView { get; private set; }
然后在你创建了你的联赛集合之后,将视图附加到你的集合上,当你在视图上设置分组:
LeaguesView = (ListCollectionView)CollectionViewSource.GetDefaultView(Leagues);
LeaguesView.GroupDesriptions.Add(new PropertyGroupDescription("NationName"));
然后,将你的DropDownButton ItemSource绑定到LeaguesView,并将你的HeaderTemplate绑定到"Name"-这是组的名称:
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
如果你想显示组中有多少项,你也可以使用ItemCount属性。