在回答其他问题时,我遇到了一件我试图理解的事情。我有一个ListView,它的ItemsSource绑定到我的页面的一个属性上。页面实现了INotifyPropertyChanged,DataContext被设置,一切正常,我可以看到我的列表渲染在屏幕上。但是如果我在其中一个元素中更改了一些东西并在整个集合上引发了属性更改,则更改不会显示在屏幕上,获取器被调用,因此绑定起作用,但是没有任何更改。
为什么会这样?是否有任何内部的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中的修改: <TextBlock Text="{Binding}" FontSize="16"/>
。
然后调用RaiseProperty(nameof(Elements));
会更新视图,即使没有修改集合。所以为什么在这种情况下绑定的工作方式不同呢?看起来它只是返回数组而没有检查变化。