延续上文,我对代码略作了改动:
(1)增加了一个ControlStyleSelector,用来调试GroupItem真正的绑定对象。
(2)实现了GroupStyle.ContainerStyle。为了调试,我先实现了一个Auto-Apply的Style,在文章最后给出了真正的实现。
数据结构:
class Data
{
public string Value { get; set; }
public string Type { get; set; }
}
XAML:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication2"
Title="MainWindow" SizeToContent="WidthAndHeight">
<Window.Resources>
<local:ControlStyleSelector x:Key="selector" />
<Style TargetType="GroupItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<StackPanel>
<Expander Header="{Binding Name}">
<ItemsPresenter />
</Expander>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate DataType="{x:Type local:Data}">
<TextBlock Text="{Binding Value}"/>
</DataTemplate>
</Window.Resources>
<StackPanel Margin="5">
<ListBox ItemsSource="{StaticResource data}">
<ListBox.GroupStyle>
<GroupStyle ContainerStyleSelector="{StaticResource selector}">
</GroupStyle>
</ListBox.GroupStyle>
</ListBox>
</StackPanel>
</Window>
代码:
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
ObservableCollection<Data> data = new ObservableCollection<Data>();
for (int i = 1; i <= 9; i += 2)
data.Add(new Data() { Value = i.ToString(), Type = "Odd" });
for (int i = 0; i < 10; i += 2)
data.Add(new Data() { Value = i.ToString(), Type = "Even" });
this.Resources.Add("data", data);
InitializeComponent();
ICollectionView vw = CollectionViewSource.GetDefaultView(data);
vw.GroupDescriptions.Add(new PropertyGroupDescription("Type"));
}
}
class ControlStyleSelector : StyleSelector
{
public override Style SelectStyle(object item, DependencyObject container)
{
return base.SelectStyle(item, container);
}
}
运行截图:
可以看到分组展开与收缩的功能已经实现,原先GroupItem下的Visual Tree中的StackPanel也已经被替换成了Expander了。在Expander内,我直接把ItensPresenter放到里面,他自动显示出了分组的内容。根据调试,其实GroupItem绑定到的是一个MS内部结构:
MS.Internal.Data.CollectionViewGroupInternal,派生自 CollectionViewGroup类型,父类提供了Name和Items属性,所以我可以用来做绑定!上面的XAML是调试性质,真真的写法应该把Style放在ListBox的GroupStyle内部,或者变成一个Resource,代码如下:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication2"
Title="MainWindow" SizeToContent="WidthAndHeight">
<Window.Resources>
<DataTemplate DataType="{x:Type local:Data}">
<TextBlock Text="{Binding Value}"/>
</DataTemplate>
</Window.Resources>
<StackPanel Margin="5">
<ListBox ItemsSource="{StaticResource data}">
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="GroupItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander Header="{Binding Name}">
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListBox.GroupStyle>
</ListBox>
</StackPanel>
</Window>