为什么绑定到 IEnumerable 的 ListBox 不更新?

Bar*_*zKP 0 c# data-binding wpf

我有以下 XAML:

<Window x:Class="ListBoxTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ListBoxTest"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:Model />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ListBox ItemsSource="{Binding Items}" Grid.Row="0"/>
        <Button Content="Add" Click="Button_Click" Grid.Row="1" Margin="5"/>
    </Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

以及该类的以下代码Model,将其放入主窗口中DataContext

public class Model : INotifyPropertyChanged
{
    public Model()
    {
        items = new Dictionary<int, string>();
    }

    public void AddItem()
    {
        items.Add(items.Count, items.Count.ToString());

        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs("Items"));
    }

    private Dictionary<int, string> items;
    public IEnumerable<string> Items { get { return items.Values; } }

    public event PropertyChangedEventHandler PropertyChanged;
}
Run Code Online (Sandbox Code Playgroud)

和主窗口的代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var model = this.DataContext as Model;
        model.AddItem();
    }
}
Run Code Online (Sandbox Code Playgroud)

按下按钮时,列表的内容不会更新。

但是,当我将属性的 getter 更改Items为:

public IEnumerable<string> Items { get { return items.Values.ToList(); } }
Run Code Online (Sandbox Code Playgroud)

它开始起作用。

然后,当我注释掉发送事件的部分时,PropertyChanged它再次停止工作,这表明事件正在正确发送。

那么,如果列表接收到事件,为什么它不能在第一个版本中正确更新其内容,而不需要调用ToList

Cle*_*ens 5

仅当属性值实际发生更改时,引发PropertyChanged属性事件才有效。Items当您引发该事件时,WPF 绑定基础结构会注意到属性 getter 返回的集合实例与以前相同,并且不执行任何更新绑定目标的操作。

但是,当您返回时items.Values.ToList(),每次都会创建一个新的集合实例,并更新绑定目标。

  • @heltonbiker即使您通知所有属性而不是特定属性的更改,也不会更新绑定目标,因为源集合实际上并未更改。 (2认同)