简体   繁体   English

通过INotifyPropertyChanged更新ListView的ItemsSource

[英]Updating ListView's ItemsSource via INotifyPropertyChanged

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. 我有一个ListViewItemsSource绑定到我的页面的属性。 The page implements INotifyPropertyChanged , the DataContext is set, evrything works, I can see my list rendered on the screen. 页面实现INotifyPropertyChangedDataContext设置,evrything工作,我可以看到我的列表在屏幕上呈现。 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. 但是如果我在其中一个元素中更改某些内容并在整个集合中提升属性,则更改在屏幕上不可见,调用getter,因此绑定有效,但没有任何更改。

Why is it so? 为什么会这样? Is there any internal ListView's optmization going on? 是否有任何内部ListView的 optmization正在进行?

The XAML code: 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>

Code behind: 代码背后:

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));
    }
}

NOTE: I know how to make it work by implementing InotifyPropertyChanged in MyItem class. 注意:我知道如何通过在MyItem类中实现InotifyPropertyChanged来使其工作。 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));
}

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

Then calling RaiseProperty(nameof(Elements)); 然后调用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. 它似乎只是返回数组而不检查更改。

Yes, the getter will be called because you are calling RaiseProperty(nameof(Elements)) . 是的,将调用getter,因为您正在调用RaiseProperty(nameof(Elements)) But nothing will get updated because the property Elements is unchanged . 但是没有什么会更新,因为属性Elements 没有变化 It's still the exact same object. 它仍然是完全相同的对象。 What's changed is its underlying object( elements[1] )'s property Name . 改变的是它的底层对象( elements[1] )的属性Name

That's why in this case the InotifyPropertyChanged needs to be implemented at the MyItem level. 这就是为什么在这种情况下需要在MyItem级别实现InotifyPropertyChanged

If you change your Elements 's type to ObservableCollection<MyItem> . 如果将Elements的类型更改为ObservableCollection<MyItem> Then when you add/remove items to/from it, the UI will get updated. 然后,当您向/从中添加/删除项目时,UI将更新。 But if the underlying MyItem 's property is changed like what you did above, the UI will still remain the same. 但是如果底层MyItem的属性像上面那样改变了,那么UI仍将保持不变。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM