WPF:将集合与分组的集合绑定到ListBox

8
有时候,WPF 对我来说太复杂了。我有一个名为“Window1”的窗口,其中包含一组“Group”。"Group" 是一个类,其中包含一组 "Person"。最终这应该是一个联系人列表。我想要做的就是在 ListBox 中显示带有其人员的组,其中列表组的组名等于我的类 "Groups" 的 Name 属性。
我尝试使用绑定到“Collection”的 CollectionViewSource。组被正确地显示,但列表项等于组名。因此,每个组只有一个项目:它的组名。
许多示例仅显示具有一个集合的项目分组。我可以将组名设置为“Person”的属性。但是,那时我无法计数(这真的很重要): - 每个组有多少人 - 其中有多少人的状态为“在线”。
我在“Group”类中使用 linq 进行计数。 感谢任何帮助我入门的建议。
2个回答

22

嗯,我不确定这是否是你想要实现的,但以下是一种你可以尝试的方法:

假设你的类是这样的:

public class Group
{
    public string Name { get; set; }
    public List<Contact> Contacts { get; set; }
}

public class Contact
{
    public string Name { get; set; }
    public bool IsOnline { get; set; }
}

你可以将 ListBox.ItemTemplate 设置为绑定到 Contacts 属性的另一个 ListBox,如下所示:

<CollectionViewSource x:Key="groups" Source="{Binding}" >
    <CollectionViewSource.GroupDescriptions>
        <PropertyGroupDescription PropertyName="Name" />
    </CollectionViewSource.GroupDescriptions>
</CollectionViewSource>

<DataTemplate x:Key="groupTemplate" DataType="Group">
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding Name}" />
    </StackPanel>
</DataTemplate>

<ListBox ItemsSource="{Binding Source={StaticResource groups}}">
    <ListBox.GroupStyle>
        <GroupStyle HeaderTemplate="{StaticResource groupTemplate}" />
    </ListBox.GroupStyle>
    <ListBox.ItemTemplate>
        <DataTemplate DataType="Contact">
            <ListBox ItemsSource="{Binding Contacts}">
                <ListBox.ItemTemplate>
                    <DataTemplate DataType="Contact">
                        <TextBlock Text="{Binding Name}" />
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

你需要对内部列表框进行一些样式设置。

编辑:另一种解决方案是使用TreeView

<DataTemplate DataType="Contact">
   <TextBlock Text="{Binding Name}" />
</DataTemplate>

<TreeView ItemsSource="{Binding Source={StaticResource groups}}">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate DataType="Group" ItemsSource="{Binding Contacts}">
            <TextBlock Text="{Binding Name}" />
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

这非常有帮助,与我的旧解决方案相当,其中每个组都有一个Expander和一个ListBox用于联系人。问题在于,您可以通过列表选择一个人,但我认为您可以只使用一个。我尝试复制Windows Live Messenger 2009联系人列表的UI。我认为他们只使用了一个ListBox和一个扩展器作为组的ControlTemplate。但我还假设他们将组定义为属性。但我真的不知道他们如何计算在线人数。顺便说一句,您的类是正确的。 - user110918
为什么不使用TreeView控件来显示分层数据? - idursun
你说得对极了!我觉得那肯定能解决我的问题。对于“为什么”的问题,我没有答案。我并没有经常使用TreeView控件。但这对我的问题来说应该是最好的选择。谢谢! - user110918
TreeView真的是我所需要的东西。 - user110918

9
如果您有一份Programming WPF的副本,请跳转至第221页。如果没有,我将以我拙劣的方式进行总结。
首先,您不需要手动对Person对象进行分组。
如果每个Person对象都有一个Group属性,
People people = // retrieve the List<Person> somehow
ICollectionView view = CollectionViewSource.GetDefaultView(people);
view.GroupDescriptions.Add( new PropertyGroupDescription("Group") );

所有继承自 ItemsControl 的控件都可以显示分组项,因此。
// the XAML
<ListBox ... ItemsSource={Binding}>
  <ListBox.GroupStyle>
    <x:Static Member="GroupStyle.Default" />
  </ListBox.GroupStyle>
</ListBox>

您还可以定义自定义GroupStyle,并指定GroupStyle.HeaderTemplate来定义一个新的DataTemplate,显示自定义属性,例如“some PropertyValue(Count)”-将一个TextBlock绑定到{Binding SomeProperty},另一个TextBlock绑定到{Binding ItemCount} 希望对您有所帮助。

首先感谢您。我的Person对象还没有group属性,我想避免使用它。我不明白如何处理计数(只是逻辑上的,TextBlock的事实很清楚)。以下是一些代码,如果可能会有所帮助。枚举在线状态{在线,离线}类人 { //每个组的标题应该计算 //多少人具有OnlineStatus“在线”。 公共在线状态状态{获取;设置;} }类组 { 公共列表<Person>人=新列表<Person>(); }类Window1{ 公共列表<组>组=新列表<组>(); } - user110918
+1,"{Binding ItemCount}"是我需要的答案!谢谢! - Dom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接