【问题标题】:Updating ListView's ItemsSource via INotifyPropertyChanged通过 INotifyPropertyChanged 更新 ListView 的 ItemsSource
【发布时间】:2015-11-09 18:16:23
【问题描述】:

在回答 other question 时,我已经进入了我试图理解的一件事。我有一个ListView,它ItemsSource 绑定到我页面的一个属性。该页面实现了INotifyPropertyChanged,设置了DataContext,一切正常,我可以看到我的列表呈现在屏幕上。但是,如果我在其中一个元素中更改某些内容并在整个集合中引发属性更改,则更改在屏幕上不可见,调用 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>

后面的代码:

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 来使其工作。我也知道,当某个项目内部发生变化时,重新加载整个集合是一种不好的模式。我只是想确认一些事情。


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

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 中的修改:&lt;TextBlock Text="{Binding}" FontSize="16"/&gt;

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

【问题讨论】:

  • 我想知道这个问题有什么问题,所以它被否决了。谁能解释一下?

标签: c# xaml windows-10 uwp windows-10-mobile


【解决方案1】:

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

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

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

【讨论】:

  • 是的,我就是这么想的。我刚刚endured at reference source 似乎绑定对源对象进行了弱引用以供将来比较。似乎我在玩 List 和 Observable 时被误导了。但是还有一件小事-如果我将元素更改为数组public string[] Elements { get; } = new string[] { "Standard", "Standard", "Standard" };(更改模板中的绑定)然后修改Elements[1] = "Modified one"; ...
  • ... 然后RaiseProperty(nameof(Elements)); 将更新视图。它可能不会改变整个数组引用,但这可能意味着绑定会在堆栈上生成元素的精确副本?然后 equals 可能会返回不同的集合,因为可能会检查所有值类型。
  • 我认为当您绑定到 Stack(不是 Heap)上的值时,绑定不会检查更改。当您调用RaiseProperty(nameof(Elements)); 事件而不更改元素时,您将看到列表视图被重新填充。
  • 有趣!我从不厌倦那个。顺便说一句List&lt;string&gt; 不起作用。
  • 但是string[] 不也是引用类型吗?
猜你喜欢
  • 2023-03-31
  • 1970-01-01
  • 2017-04-12
  • 1970-01-01
  • 1970-01-01
  • 2014-01-26
  • 2014-05-22
  • 2019-04-22
  • 1970-01-01
相关资源
最近更新 更多