在 WPF 中通过分组绑定列表框
我有一个 ViewModel 集合,想要将 ListBox 绑定到它们。经过一些调查,我发现了这个。
所以我的 ViewModel 看起来像这样(伪代码)
interface IItemViewModel
{
string DisplayName { get; }
}
class AViewModel : IItemViewModel
{
string DisplayName { return "foo"; }
}
class BViewModel : IItemViewModel
{
string DisplayName { return "foo"; }
}
class ParentViewModel
{
IEnumerable<IItemViewModel> Items
{
get
{
return new IItemViewModel[] {
new AItemViewModel(),
new BItemViewModel()
}
}
}
}
class GroupViewModel
{
static readonly GroupViewModel GroupA = new GroupViewModel(0);
static readonly GroupViewModel GroupB = new GroupViewModel(1);
int GroupIndex;
GroupViewModel(int groupIndex)
{
this.GroupIndex = groupIndex;
}
string DisplayName
{
get { return "This is group " + GroupIndex.ToString(); }
}
}
class ItemGroupTypeConverter : IValueConverter
{
object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is AItemViewModel)
return GroupViewModel.GroupA;
else
return GroupViewModel.GroupB;
}
}
并且这个 XAML
<UserControl.Resources>
<vm:ItemsGroupTypeConverter x:Key="ItemsGroupTypeConverter "/>
<CollectionViewSource x:Key="GroupedItems" Source="{Binding Items}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription Converter="{StaticResource ItemsGroupTypeConverter }"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</UserControl.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource GroupedItems}}">
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" FontWeight="bold" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
可以以某种方式工作,除了 HeaderTemplate 的绑定不起作用这一事实。无论如何,我宁愿省略 TypeConverter 和 CollectionViewSource。没有办法使用 ViewModel 的属性进行分组吗?
我知道在这个示例场景中,很容易用字符串替换 GroupViewModel 并让它工作,但这不是一个选项。那么如何将 HeaderTemplate 绑定到 GroupViewModel 呢?
I've got a collection of ViewModels and want to bind a ListBox to them. Doing some investigation I found this.
So my ViewModel look like this (Pseudo Code)
interface IItemViewModel
{
string DisplayName { get; }
}
class AViewModel : IItemViewModel
{
string DisplayName { return "foo"; }
}
class BViewModel : IItemViewModel
{
string DisplayName { return "foo"; }
}
class ParentViewModel
{
IEnumerable<IItemViewModel> Items
{
get
{
return new IItemViewModel[] {
new AItemViewModel(),
new BItemViewModel()
}
}
}
}
class GroupViewModel
{
static readonly GroupViewModel GroupA = new GroupViewModel(0);
static readonly GroupViewModel GroupB = new GroupViewModel(1);
int GroupIndex;
GroupViewModel(int groupIndex)
{
this.GroupIndex = groupIndex;
}
string DisplayName
{
get { return "This is group " + GroupIndex.ToString(); }
}
}
class ItemGroupTypeConverter : IValueConverter
{
object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is AItemViewModel)
return GroupViewModel.GroupA;
else
return GroupViewModel.GroupB;
}
}
And this XAML
<UserControl.Resources>
<vm:ItemsGroupTypeConverter x:Key="ItemsGroupTypeConverter "/>
<CollectionViewSource x:Key="GroupedItems" Source="{Binding Items}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription Converter="{StaticResource ItemsGroupTypeConverter }"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</UserControl.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource GroupedItems}}">
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" FontWeight="bold" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This works somehow, exept of the fact that the binding of the HeaderTemplate does not work. Anyhow I'd prefer omitting the TypeConverter and the CollectionViewSource. Isn't there a way to use a property of the ViewModel for Grouping?
I know that in this sample scenario it would be easy to replace the GroupViewModel with a string an have it working, but that's not an option. So how can I bind the HeaderTemplate to the GroupViewModel?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好吧,我终于自己解决了。
首先,TypeConverter 是不必要的,因为 PropertyGroupDescription 可以绑定在 PropertyName 上。因此,我向 IItemViewModel 添加了属性“Group”,并修改了 XAML,如下所示:
此外,HeaderTemplate 的 DataContext 是 CollectionViewGroupInternal,并且绑定必须如下所示:
这里 CollectionViewGroupInternal.Name 解析实际的 GroupViewModel。
Ok, I finally solved it myself.
First of all the TypeConverter is unnecessary, because the PropertyGroupDescription can be bound on a PropertyName. So I added a Property 'Group' to IItemViewModel and modified XAML as follows:
Furthermore the HeaderTemplate's DataContext is a CollectionViewGroupInternal and the binding has to look like this:
Here CollectionViewGroupInternal.Name resolves the actual GroupViewModel.