无法在 DropDownButton 中组织数据
Not able to organize data in DropDownButton
总结
我有一个 DropDownButton
,其中包含特定国家/地区的所有联赛。所以基本上 select 来自 ComboBox
的 Nation
和 selected Nation
的 Leagues
将被添加到 DropDownButton
.直到这里没问题。
我需要做的是:为Nation
整理DropDownButton
里面的Leagues
。想象一下,在 DropDownButton
我有这个组织:
Italy
Item1
Item2
Item3
England
Item1
Item2
Spain
Item1
Item2
... etc ...
项目类型
如何查看项目是按国家/地区组织的。在解释我为实现此结果所做的工作之前,我不得不说我使用的是 CheckedListItem
class,本质上是将 CheckBox
绑定到项目的 class的 DropDownButton
。这个 class 很简单:
public class CheckedListItem<T> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool isChecked;
private T item;
public CheckedListItem() { }
public CheckedListItem(T item, bool isChecked = false)
{
this.item = item;
this.isChecked = isChecked;
}
public T Item
{
get { return item; }
set
{
item = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item"));
}
}
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsChecked"));
}
}
}
基本上使 Item<T>
可用,如果是 selected。为了使它在 XAML
中工作,我在 Window.Resources
:
中编写了这段代码
<DataTemplate x:Key="NormalItemTemplate">
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Item.Name}"
x:Name="Leagues" Checked="Leagues_Checked" Unchecked="Leagues_Unchecked" />
</DataTemplate>
<DataTemplate x:Key="SelectionBoxTemplate" >
<TextBlock Text="{DynamicResource displayedNation}"/>
</DataTemplate>
<DataTemplate x:Key="CombinedTemplate">
<ContentPresenter x:Name="Presenter" Content="{Binding}" ContentTemplate="{StaticResource NormalItemTemplate}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, Controls:DropDownButton, 1}}"
Value="{x:Null}">
<Setter TargetName="Presenter" Property="ContentTemplate"
Value="{StaticResource SelectionBoxTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<!--This is for the group item !-->
<Style TargetType="{x:Type GroupItem}" x:Key="containerStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<!--Here, we tell that each group of item will be placed under Expander control,
and this expander control will by default will have style we defined in above code.-->
<Expander IsExpanded="False" x:Name="ComboExpander" Header="{TemplateBinding Content}"
HeaderTemplate="{TemplateBinding ContentTemplate}">
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
说明问题
现在为了实现 DropDownButton
中的分组,我首先在 Window.Resource
中创建了一个 CollectionViewSource
,如下所示:
<CollectionViewSource Source="{Binding Leagues}" x:Key="GroupedData">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Item.Country" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<DataTemplate x:Key="GroupHeader">
<TextBlock Text="{Binding Name}" Margin="10,0,0,0" Foreground="#989791"/>
</DataTemplate>
在DropDownButton
中我设置了这个结构:
<Controls:DropDownButton Content="Leagues" x:Name="LeagueMenu"
ItemsSource="{Binding Source={StaticResource GroupedData}}"
ItemTemplate="{StaticResource CombinedTemplate}" >
<Controls:DropDownButton.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource containerStyle}"
HeaderTemplate="{StaticResource GroupHeader}">
</GroupStyle>
</Controls:DropDownButton.GroupStyle>
</Controls:DropDownButton>
(请注意,我使用的是 MahApp)
所以基本上我为 CheckedListItem
添加了一个模板,作为 ItemSource
GroupedData
你如何从上面的代码中看到绑定 ObservableCollection
of [=21] =].
数据人口
当 Nation
被 select 编辑时,可用于 select 编辑 Nations
的 Leagues
列表将被添加到 DropDownButton
,实现代码:
private ObservableCollection<CheckedListItem<League>> _leagues = new ObservableCollection<CheckedListItem<League>>();
public ObservableCollection<CheckedListItem<League>> Leagues
{
get
{
return _leagues;
}
set
{
_leagues = value;
OnPropertyChanged();
}
}
添加 selected Nation
的 League
调用的方法是这样的:
public void GetLeagues(string link, string nation)
{
Task.Run(() =>
{
var leagues = //get some collection
foreach (var league in leagues)
{
var championship = new CheckedListItem<League>();
championship.Item = new League { Name = league.Name, Link = league.Link, Country = nation };
_leagues.Add(championship);
}
});
}
基本上我创建了一个 League
的 CheckedListItem
作为模型包含这个 属性:
public class League
{
public string Name { get; set; }
public string Link { get; set; }
public string Country { get; set; }
}
应该出现的结果是这样的:
但是我得到了这个结果:
如您所见,我没有名称为 Nation
的 header 分组。我在 XAML 或代码中也没有错误,所以我不知道为什么 header 没有出现。
我知道这个问题可能有点复杂,所以如果有任何问题或更多细节,请问我,我会尽力回答。
演示解决方案:
https://mega.nz/#!g4YlTL4A!G4WXy1t64Q4yImYNvzgwGbieX1mhKnXO2OiuAO3FDg0
我不会尝试让第三方控件工作,而是改变工作方式 ComboBox
以满足您的需要:
MainWindow.xaml
<Controls:MetroWindow x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="700" Width="525">
<Window.Resources>
<ResourceDictionary>
<CollectionViewSource Source="{Binding Leagues}" x:Key="GroupedData">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Item.Country" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<DataTemplate x:Key="GroupHeader">
<TextBlock Text="{Binding Name}" Margin="10,0,0,0" Foreground="#989791"/>
</DataTemplate>
<Style TargetType="{x:Type GroupItem}" x:Key="containerStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="False" x:Name="ComboExpander" Header="{TemplateBinding Content}"
HeaderTemplate="{StaticResource GroupHeader}">
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="NormalItemTemplate">
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Item.Name}" x:Name="Leagues" />
</DataTemplate>
<DataTemplate x:Key="HeaderTemplate">
<TextBlock Text="Campionati"/>
</DataTemplate>
<DataTemplate x:Key="CombinedTemplate">
<ContentPresenter x:Name="Presenter"
Content="{Binding}"
ContentTemplate="{StaticResource NormalItemTemplate}" />
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource FindAncestor, ComboBoxItem, 1}}"
Value="{x:Null}">
<Setter TargetName="Presenter" Property="ContentTemplate"
Value="{StaticResource HeaderTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ComboBox x:Name="LeagueMenuComboBox"
ItemsSource="{Binding Source={StaticResource GroupedData}}"
ItemTemplate="{StaticResource CombinedTemplate}"
HorizontalContentAlignment="Center">
<ComboBox.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource containerStyle}"
HeaderTemplate="{StaticResource GroupHeader}">
</GroupStyle>
</ComboBox.GroupStyle>
</ComboBox>
</Grid>
</Controls:MetroWindow>
总结
我有一个 DropDownButton
,其中包含特定国家/地区的所有联赛。所以基本上 select 来自 ComboBox
的 Nation
和 selected Nation
的 Leagues
将被添加到 DropDownButton
.直到这里没问题。
我需要做的是:为Nation
整理DropDownButton
里面的Leagues
。想象一下,在 DropDownButton
我有这个组织:
Italy
Item1
Item2
Item3
England
Item1
Item2
Spain
Item1
Item2
... etc ...
项目类型
如何查看项目是按国家/地区组织的。在解释我为实现此结果所做的工作之前,我不得不说我使用的是 CheckedListItem
class,本质上是将 CheckBox
绑定到项目的 class的 DropDownButton
。这个 class 很简单:
public class CheckedListItem<T> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool isChecked;
private T item;
public CheckedListItem() { }
public CheckedListItem(T item, bool isChecked = false)
{
this.item = item;
this.isChecked = isChecked;
}
public T Item
{
get { return item; }
set
{
item = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item"));
}
}
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsChecked"));
}
}
}
基本上使 Item<T>
可用,如果是 selected。为了使它在 XAML
中工作,我在 Window.Resources
:
<DataTemplate x:Key="NormalItemTemplate">
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Item.Name}"
x:Name="Leagues" Checked="Leagues_Checked" Unchecked="Leagues_Unchecked" />
</DataTemplate>
<DataTemplate x:Key="SelectionBoxTemplate" >
<TextBlock Text="{DynamicResource displayedNation}"/>
</DataTemplate>
<DataTemplate x:Key="CombinedTemplate">
<ContentPresenter x:Name="Presenter" Content="{Binding}" ContentTemplate="{StaticResource NormalItemTemplate}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, Controls:DropDownButton, 1}}"
Value="{x:Null}">
<Setter TargetName="Presenter" Property="ContentTemplate"
Value="{StaticResource SelectionBoxTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<!--This is for the group item !-->
<Style TargetType="{x:Type GroupItem}" x:Key="containerStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<!--Here, we tell that each group of item will be placed under Expander control,
and this expander control will by default will have style we defined in above code.-->
<Expander IsExpanded="False" x:Name="ComboExpander" Header="{TemplateBinding Content}"
HeaderTemplate="{TemplateBinding ContentTemplate}">
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
说明问题
现在为了实现 DropDownButton
中的分组,我首先在 Window.Resource
中创建了一个 CollectionViewSource
,如下所示:
<CollectionViewSource Source="{Binding Leagues}" x:Key="GroupedData">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Item.Country" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<DataTemplate x:Key="GroupHeader">
<TextBlock Text="{Binding Name}" Margin="10,0,0,0" Foreground="#989791"/>
</DataTemplate>
在DropDownButton
中我设置了这个结构:
<Controls:DropDownButton Content="Leagues" x:Name="LeagueMenu"
ItemsSource="{Binding Source={StaticResource GroupedData}}"
ItemTemplate="{StaticResource CombinedTemplate}" >
<Controls:DropDownButton.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource containerStyle}"
HeaderTemplate="{StaticResource GroupHeader}">
</GroupStyle>
</Controls:DropDownButton.GroupStyle>
</Controls:DropDownButton>
(请注意,我使用的是 MahApp)
所以基本上我为 CheckedListItem
添加了一个模板,作为 ItemSource
GroupedData
你如何从上面的代码中看到绑定 ObservableCollection
of [=21] =].
数据人口
当 Nation
被 select 编辑时,可用于 select 编辑 Nations
的 Leagues
列表将被添加到 DropDownButton
,实现代码:
private ObservableCollection<CheckedListItem<League>> _leagues = new ObservableCollection<CheckedListItem<League>>();
public ObservableCollection<CheckedListItem<League>> Leagues
{
get
{
return _leagues;
}
set
{
_leagues = value;
OnPropertyChanged();
}
}
添加 selected Nation
的 League
调用的方法是这样的:
public void GetLeagues(string link, string nation)
{
Task.Run(() =>
{
var leagues = //get some collection
foreach (var league in leagues)
{
var championship = new CheckedListItem<League>();
championship.Item = new League { Name = league.Name, Link = league.Link, Country = nation };
_leagues.Add(championship);
}
});
}
基本上我创建了一个 League
的 CheckedListItem
作为模型包含这个 属性:
public class League
{
public string Name { get; set; }
public string Link { get; set; }
public string Country { get; set; }
}
应该出现的结果是这样的:
但是我得到了这个结果:
如您所见,我没有名称为 Nation
的 header 分组。我在 XAML 或代码中也没有错误,所以我不知道为什么 header 没有出现。
我知道这个问题可能有点复杂,所以如果有任何问题或更多细节,请问我,我会尽力回答。
演示解决方案:
https://mega.nz/#!g4YlTL4A!G4WXy1t64Q4yImYNvzgwGbieX1mhKnXO2OiuAO3FDg0
我不会尝试让第三方控件工作,而是改变工作方式 ComboBox
以满足您的需要:
MainWindow.xaml
<Controls:MetroWindow x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="700" Width="525">
<Window.Resources>
<ResourceDictionary>
<CollectionViewSource Source="{Binding Leagues}" x:Key="GroupedData">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Item.Country" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<DataTemplate x:Key="GroupHeader">
<TextBlock Text="{Binding Name}" Margin="10,0,0,0" Foreground="#989791"/>
</DataTemplate>
<Style TargetType="{x:Type GroupItem}" x:Key="containerStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="False" x:Name="ComboExpander" Header="{TemplateBinding Content}"
HeaderTemplate="{StaticResource GroupHeader}">
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="NormalItemTemplate">
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Item.Name}" x:Name="Leagues" />
</DataTemplate>
<DataTemplate x:Key="HeaderTemplate">
<TextBlock Text="Campionati"/>
</DataTemplate>
<DataTemplate x:Key="CombinedTemplate">
<ContentPresenter x:Name="Presenter"
Content="{Binding}"
ContentTemplate="{StaticResource NormalItemTemplate}" />
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource FindAncestor, ComboBoxItem, 1}}"
Value="{x:Null}">
<Setter TargetName="Presenter" Property="ContentTemplate"
Value="{StaticResource HeaderTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ComboBox x:Name="LeagueMenuComboBox"
ItemsSource="{Binding Source={StaticResource GroupedData}}"
ItemTemplate="{StaticResource CombinedTemplate}"
HorizontalContentAlignment="Center">
<ComboBox.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource containerStyle}"
HeaderTemplate="{StaticResource GroupHeader}">
</GroupStyle>
</ComboBox.GroupStyle>
</ComboBox>
</Grid>
</Controls:MetroWindow>