c# - 使用 Wpf .NET 6 和 CommunityToolkit.Mvvm 包显示 ObservableGroupedCollection<string, TElement> 的正确方法

标签 c# .net wpf xaml community-toolkit-mvvm

Wpf .NET 6 中的 ObservableGroupedCollection

这个问题基于:

  • 使用 .NET 6Wpf 项目
  • ObservableGroupedCollection<TKey, TElement>来自 Microsoft 的 NuGet 包“CommunityToolkit.Mvvm”
  • 严格遵守MVVM模式

同时修补相对较新的 CommunityToolkit.Mvvm我遇到了ObservableGroupedCollection<TKey, TElement>在 Wpf 中,该类是相当未记录的。我的 Wpf 知识充其量只是很差 - 我打算将其用作学习项目 - 并且我无法将现有的 UWP xaml 代码转移到工作的 Wpf 示例应用程序中。
上面的博客文章中引用的示例应用程序使用 CollectionViewSource绑定(bind)到ObservableGroupedCollection<TKey, TElement>在可滚动控件中显示分组的联系人列表。我尝试在 Wpf .NET 6 应用程序中复制此行为,结果仅显示每个集合的第一个值,而不是整个范围。

在遵守 MVVM 模式的同时以分组方式显示所有条目的正确方法是什么?!

下图左侧显示了 Microsoft Store 示例应用程序的摘录,右侧显示了所需的结果。

SampleApp vs Desired

下面示例代码的结果

手动迭代组及其集合时的结果:

<表类=“s-表”> <标题> A B E F W <正文> a_2 b_0 e_0 f_0 w_1 a_1 f_1 w_0 a_0 f_2

实际ListView中显示的值:

<表类=“s-表”> <标题> A B E F W <正文> a_2 b_0 e_0 f_0 w_1

Displayed values这些显然是从集合的“顶部”刮掉的值。

让我困惑的是 SemanticZoom原文中使用Sample App (.xaml - UWP)以及相应的ViewModel.cs以某种方式能够显示所有条目,而不是刮掉集合的第一个元素。同时仍然使用基于模型的DataTemplate .

示例代码

以下代码是一个快速但肮脏的示例应用程序,用于说明我的问题并为可能的参与者提供基础。

要求:

  • Wpf 项目 -> .NET 6
  • NuGet 软件包:Microsoft 的 CommunityToolkit.Mvvm
  • 2 个新文件夹:Models 和 ViewModels
  • “yourRootNamespace”的所有实例替换为您的实际根命名空间

SomeModel.cs

namespace "yourRootNamespace".Models;

public class SomeModel
{

    public string SomeString { get; set; }

    public SomeModel(string _s)
    {
        SomeString = _s;
    }
}

MainWindowViewModel.cs

using CommunityToolkit.Mvvm.Collections;
using CommunityToolkit.Mvvm.ComponentModel;
using "yourRootNamespace".Models;
using System.Collections.Generic;
using System.Linq;

namespace "yourRootNamespace".ViewModels;

public partial class MainWindowViewModel : ObservableObject
{

    [ObservableProperty]
    private ObservableGroupedCollection<string, SomeModel>? m_someObservableGroupedCollection;

    public MainWindowViewModel()
    {
        List<SomeModel> tempList = new List<SomeModel>()
        {
            new SomeModel("w_1"),
            new SomeModel("b_0"),
            new SomeModel("a_2"),
            new SomeModel("e_0"),
            new SomeModel("f_0"),
            new SomeModel("f_1"),
            new SomeModel("a_1"),
            new SomeModel("a_0"),
            new SomeModel("w_0"),
            new SomeModel("f_2")
        };

        m_someObservableGroupedCollection = new ObservableGroupedCollection<string, SomeModel>(tempList
            .GroupBy(c => char.ToUpperInvariant(c.SomeString[0]).ToString())
            .OrderBy(g => g.Key));
    }
}

MainWindow.xaml.cs

using "yourRootNamespace".ViewModels;
using System.Windows;

namespace "yourRootNamespace";

public partial class MainWindow : Window
{

    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainWindowViewModel();
    }
}

MainWindow.xaml

<Window x:Class=""yourRootNamespace".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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:"yourRootNamespace""
        xmlns:collections="clr-namespace:CommunityToolkit.Mvvm.Collections;assembly=CommunityToolkit.Mvvm"
        xmlns:viewmodels="clr-namespace:"yourRootNamespace".ViewModels"
        xmlns:models="clr-namespace:"yourRootNamespace".Models"
        d:DataContext="{d:DesignInstance Type=viewmodels:MainWindowViewModel}"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.Resources>

        <CollectionViewSource
            x:Key="SomeListViewSource"
            Source="{Binding SomeObservableGroupedCollection}"
            IsLiveGroupingRequested="True"/>

        <DataTemplate
            x:Key="SomeTemplate"
            DataType="{x:Type models:SomeModel}">
            <TextBlock Text="{Binding SomeString}"/>
        </DataTemplate>

    </Window.Resources>

    <Grid>
        <ListView
            ItemTemplate="{StaticResource SomeTemplate}"
            ItemsSource="{Binding Source={StaticResource SomeListViewSource}, Mode=OneWay}"
            SelectionMode="Single">
            <ListView.GroupStyle>
                <GroupStyle
                    HidesIfEmpty="True">
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate
                            DataType="{x:Type collections:IReadOnlyObservableGroup}">
                            <TextBlock Text="{Binding Key}"/>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                </GroupStyle>
            </ListView.GroupStyle>
        </ListView>
    </Grid>

</Window>

最佳答案

我不确定 CommunityToolkit 开发人员的意图,它通过将 CollectionViewSource.GroupDescriptions 指定为 CollectionViewSource 来工作。

<Window.Resources>
    <CollectionViewSource x:Key="SomeListViewSource"
                          Source="{Binding SomeObservableGroupedCollection}"
                          IsLiveGroupingRequested="True">
        <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="Key"/>
        </CollectionViewSource.GroupDescriptions>
    </CollectionViewSource>

    <DataTemplate x:Key="SomeTemplate">
        <TextBlock Text="{Binding SomeString}"/>
    </DataTemplate>
</Window.Resources>

<Grid>
    <ListView ItemTemplate="{StaticResource SomeTemplate}"
              ItemsSource="{Binding Source={StaticResource SomeListViewSource}, Mode=OneWay}"
              SelectionMode="Single">
        <ListView.GroupStyle>
            <GroupStyle HidesIfEmpty="True">
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Foreground="Red"
                                   Text="{Binding Name}"/>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
            </GroupStyle>
        </ListView.GroupStyle>
    </ListView>
</Grid>

关于c# - 使用 Wpf .NET 6 和 CommunityToolkit.Mvvm 包显示 ObservableGroupedCollection<string, TElement> 的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74425290/

相关文章:

.net - AppDomain 地址空间

c# - 如何将构建限制为仅支持 EN "Microsoft.Expression.Interactions.resources.dll"并避免 DE、KR、FR、ES 等...?

wpf - 在 WPF 数据网格中使行不可聚焦

c# - MongoDB 在正则表达式查询中使用索引

c# - 如何等待 WCF 代理客户端准备好?

c# - 我调用的是 .NET 对象还是 COM 对象?

c# - 图表控件 : Stacked Column Series Label Positioning

c# - 更改 ViewModel 外部的 TextBox.Text

c# - 有条件地传递参数

c# - 如何在 DataColumn.Expression 中使用 IF/ELSE 或 CASE?