如何使用 AdvancedCollectionView 源更新 UWP ListView 中的项目

How to update item in UWP ListView with AdvancedCollectionView source

我正在使用 Windows 社区工具包中的 AdvanceCollectionView 作为 XAML ListView 的来源,以允许排序和过滤。我在更新 ListView 时遇到问题。

为了重现这个问题,我创建了一个简单的 Person class。在 MainPage XAML 中,我有一个 ListView MyXAMLList 和一个 Button EditButton。在 MainPage 代码中,我有一个 ObservableCollection<Person> MyPersonListAdvancedCollectionView MyPersonACV。在 Page_Loaded 事件中,我将一个人添加到列表中并使用 AdvancedCollectionView 作为列表视图的来源:

Person p = new Person
{
    Name = "John",
    Age = 35
};

MyPersonList.Add(p);
MyPersonACV = new AdvancedCollectionView(MyPersonList, true);
MyXAMLList.ItemsSource = MyPersonACV;    

这行得通,我可以在列表中看到约翰。

EditButton 代码中,我尝试更新列表中的项目,但这不起作用。 ObservableCollection 和 AdvancedCollectionView 均已更新,但 XAML 列表仍显示旧名称“John”而不是“Mary”。

MyPersonList[0].Name = "Mary";

Debug.WriteLine(MyPersonList[0].ToString());
Debug.WriteLine(MyPersonACV[0].ToString());
        

我尝试更新 MyXAMLList.SelectedItem,但结果相同:

Person p = (Person)MyXAMLList.SelectedItem;
p.Name = "Mary";

我也试过添加 MyPersonACV.Refresh(); 但没有帮助。

我做错了什么?如何更新列表中的项目?

完整代码如下

人class:

class Person
{
    public string Name {get; set;}
    public int Age { get; set; }
    public override string ToString()
    {
        return Name;
    }
}

主页XAML:

<Page
    x:Class="App3.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App3"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    Loaded="Page_Loaded">

    <Grid>
        <StackPanel Orientation="Vertical">
            <ListView Height="Auto" Width="Auto" x:Name="MyXAMLList" SelectionMode="Single" IsItemClickEnabled="True"/>
            <StackPanel Orientation="Horizontal">
                <Button x:Name="EditButton" Content="Edit" Click="EditButton_Click"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</Page>

主页 cs:

using Microsoft.Toolkit.Uwp.UI;
using System.Collections.ObjectModel;
using System.Diagnostics;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;


namespace App3
{

    public sealed partial class MainPage : Page
    {

        private ObservableCollection<Person> MyPersonList = new ObservableCollection<Person>();
        private AdvancedCollectionView MyPersonACV;

        public MainPage()
        {
            this.InitializeComponent();
        }


        private void EditButton_Click(object sender, RoutedEventArgs e)
        {

            //Change name
            MyPersonList[0].Name = "Mary";
            //Person p = (Person)MyXAMLList.SelectedItem;
            //p.Name = "Mary";

            Debug.WriteLine(MyPersonList[0].ToString());
            Debug.WriteLine(MyPersonACV[0].ToString());

            //MyPersonACV.Refresh();

        }

        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
           //create person 
           Person p = new Person
           {
               Name = "John",
               Age = 35
           };
           //add to list
           MyPersonList.Add(p);
           
           //set up ListView source
           MyPersonACV = new AdvancedCollectionView(MyPersonList, true);
           MyXAMLList.ItemsSource = MyPersonACV;
        }
        

    }
}

我注意到您覆盖了 ToString() 方法来显示 ListView 的每个项目。更新Name属性时,即使Name属性的值更新了,因为Name属性和ListViewItem之间没有绑定关系,ToString()方法也没有更新数据时触发,UI 未更新。最好使用 DataTemplate 自定义项目的外观,将名称 属性 绑定到元素(例如 TetxBlock)并实现 INotifyPropertyChanged界面。在这种情况下,当 Name proeprty 更改时,它将向绑定提供更改通知并且 UI 将更新。例如:

.xaml:

<ListView Height="Auto" Width="Auto" x:Name="MyXAMLList" SelectionMode="Single" IsItemClickEnabled="True">
    <ListView.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Name}"></TextBlock>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

.cs:

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    private string name { get; set; }
    public string Name 
    {
        get 
        {
            return name;
        }
        set 
        {
            name = value;
            OnPropertyChanged();
        }
    }
    public int Age { get; set; }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

private void EditButton_Click(object sender, RoutedEventArgs e)
{
    //Change name
    MyPersonList[0].Name = "Mary";
}