解决方案的基本原理是在ListBox 的ItemTemplate 中使用另一个ItemsControl。这个ItemsControl 应该有一个水平方向的StackPanel 作为它的ItemsPanel。
这是一个基本示例。让我们从一些非常简单的测试数据开始:-
public class TestStringList : List<string>
{
public TestStringList()
{
AddRange(new[] {"Anthony", "Kar", "Martin", "Jon", "Erik", "Darin",
"Balus", "Mike", "Hans", "Alex", "Anomie", "David" });
}
}
现在我们想在 ListBox 中显示这个列表,但保留所有首字母相同的名称在同一行。我将使用IValueConverter 的实现来处理我们需要的分组。如果您使用的是 MVVM,那么您的 ViewModel 就可以使用它。
public class Grouper : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((IEnumerable<string>)value).OrderBy(s => s).GroupBy(s => s[0]);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
这个转换器的输出基本上是IEnumerable<IEnumerable<string>>,这就是我们想要的。外部 ListBox 将枚举外部集合,内部 ItemsControl 将枚举内部字符串集,这些字符串将是一组具有相同首字母的名称。
这里是 xaml:-
<UserControl x:Class="SilverlightApplication1.SimpleGrouping"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SilverlightApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<local:TestStringList x:Key="TestData" />
<local:Grouper x:Key="grouper" />
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<ListBox ItemsSource="{Binding Converter={StaticResource grouper}, Source={StaticResource TestData}}">
<ListBox.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Margin="5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>