为什么ListBox绑定到IEnumerable更新?

问题描述:

我有以下XAML:为什么ListBox绑定到IEnumerable更新?

<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> 

,为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; 
} 

和主窗口中的代码:

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

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

按下按钮时,列表中的内容为否正在更新。

然而,当我改变Items属性的getter这样:

public IEnumerable<string> Items { get { return items.Values.ToList(); } } 

它开始工作。

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

因此,如果列表收到事件,为什么不能在第一个版本中正确更新它的内容,而不需要拨打ToList

+3

你有没有考虑过使用ObservableCollection? – heltonbiker

+0

@heltonbiker它有严重的缺点 - 像缺少“AddRange”,也没有其他可能性执行批量更新,这不会导致每个添加项目的更新。另外,我有一本字典不是一个普通的列表。 – BartoszKP

+0

@BartoszKP有可用的可观察字典的实现(只需搜索ObservableDictionary)。您可以将ListBox的ItemsSource直接绑定到ObservableDictionary,并将ListBox项目(在ItemTemplate中)绑定到字典条目的'Value'属性。 – Clemens

提高Items属性的PropertyChanged事件仅在属性值实际发生更改时才有效。在引发事件时,WPF绑定基础结构注意到属性getter返回的集合实例与之前相同,并且不会更新绑定目标。

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

+0

似乎我完全误解了'PropertyChanged'是什么:)这完全有道理,在我正在阅读有关该主题的内容中。谢谢! – BartoszKP

+0

我不知道它是否正好相关,但有时会调用'NotifyPropertyChanged(null)'(使用null作为参数而不是属性名称),屏幕上的_every_属性会更新。它为我过去解决了一些问题。 – heltonbiker

+2

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