通过 INotifyPropertyChanged 更新 ListView 的 ItemsSource

Rom*_*asz 3 c# xaml windows-10 windows-10-mobile uwp

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

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

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>
Run Code Online (Sandbox Code Playgroud)

后面的代码:

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

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


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

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

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

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

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

Jus*_* XL 5

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

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

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

  • 但是`string[]` 不也是一个引用类型吗? (2认同)