通过 INotifyPropertyChanged 更新 ListView 的 ItemsSource [英] Updating ListView's ItemsSource via INotifyPropertyChanged

查看:26
本文介绍了通过 INotifyPropertyChanged 更新 ListView 的 ItemsSource的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在回答其他问题时,我尝试了解一件事.我有一个 ListView,它 ItemsSource 绑定到我的页面的一个属性.页面实现了INotifyPropertyChanged,设置了DataContext,一切正常,我可以在屏幕上看到我的列表.但是,如果我更改其中一个元素中的某些内容并提高整个集合上的属性更改,则更改在屏幕上不可见,会调用 getter,因此绑定有效,但没有任何变化.

While answering other question I've stepped into one thing I try to understand. I've a ListView, which ItemsSource is bound to a property of my page. The page implements INotifyPropertyChanged, the DataContext is set, evrything works, I can see my list rendered on the screen. But if I change something inside one of the elements and raise property changed on the whole collection, the change is not visible on the screen, the getter is called, so the binding works, but nothing changes.

为什么会这样?是否有任何内部 ListView 的 优化正在进行?

Why is it so? Is there any internal ListView's optmization going on?

XAML 代码:

<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ListView ItemsSource="{Binding Elements}" Height="400">
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}" FontSize="16"/>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    <Button Content="Modify item" Click="Button_Click"/>
</StackPanel>

背后的代码:

public class MyItem
{
    public string Name { get; set; }
    public MyItem(string name) { this.Name = name; }
}

public sealed partial class MainPage : Page, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void RaiseProperty(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

    private List<MyItem> elements = new List<MyItem> { new MyItem("Standard"), new MyItem("Standard"), new MyItem("Standard") };
    public List<MyItem> Elements { get { Debug.WriteLine("Collection getter"); return elements; } }

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

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        elements[1].Name = "Modified one";
        RaiseProperty(nameof(Elements));
    }
}

注意:我知道如何通过在 MyItem 类中实现 InotifyPropertyChanged 使其工作.我也知道,当某个项目内部发生变化时,重新加载整个集合是一种糟糕的模式.我只是想确保一些事情.

NOTE: I know how to make it work by implementing InotifyPropertyChanged in MyItem class. I also know that it's a bad pattern to reload whole collection when something changed inside one its item. I just want to ensure about some things.

其他情况 - 似乎绑定制作了源对象的引用副本,这很清楚.但有趣的是,当我绑定到字符串数组时:

Other case - it seems that binding makes a reference copy of source object, that's clear. But interesting is that when I bind to array of strings:

public string[] Elements { get; } = new string[] { "Standard", "Standard", "Standard" };

private void Button_Click(object sender, RoutedEventArgs e)
{
    Elements[1] = "Modified one";
    RaiseProperty(nameof(Elements));
}

XAML 中的修改:<TextBlock Text="{Binding}" FontSize="16"/>.

Modification in XAML: <TextBlock Text="{Binding}" FontSize="16"/>.

然后调用 RaiseProperty(nameof(Elements)); 更新视图,即使不修改集合.那么为什么在这种情况下绑定的工作方式不同呢?似乎它只是简单地返回数组而不检查更改.

Then calling RaiseProperty(nameof(Elements)); updates the view, even without modifying the collection. So why binding works different way in this case? It seems that it simply returns array without checking for changes.

推荐答案

是的,getter 将被调用,因为您正在调用 RaiseProperty(nameof(Elements)).但是什么都不会更新,因为Elements 属性未更改.它仍然是完全相同的对象.改变的是它的底层对象(elements[1])的属性Name.

Yes, the getter will be called because you are calling RaiseProperty(nameof(Elements)). But nothing will get updated because the property Elements is unchanged. It's still the exact same object. What's changed is its underlying object(elements[1])'s property Name.

这就是为什么在这种情况下需要在 MyItem 级别实现 InotifyPropertyChanged.

That's why in this case the InotifyPropertyChanged needs to be implemented at the MyItem level.

如果您将 Elements 的类型更改为 ObservableCollection.然后,当您向其中添加/删除项目时,UI 将得到更新.但是,如果基础 MyItem 的属性像您上面所做的那样更改,则 UI 仍将保持不变.

If you change your Elements's type to ObservableCollection<MyItem>. Then when you add/remove items to/from it, the UI will get updated. But if the underlying MyItem's property is changed like what you did above, the UI will still remain the same.

这篇关于通过 INotifyPropertyChanged 更新 ListView 的 ItemsSource的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆