【问题标题】:observable collection and inotifypropertychanged可观察的集合和 inotifypropertychanged
【发布时间】:2015-06-11 07:34:10
【问题描述】:

在引发 CollectionChanged 事件时,ObservableCollection 是自包含的,因为它实现了 INotifyPropertyChanged 和 INotifyCollectionChanged。所以我认为,我们不需要再次实现 INotifyPropertyChanged。

但是我看到了一些例子,人们将 ObservableCollection 定义为属性并在 setter 中引发属性更改事件。我不明白为什么要再次执行此操作,或者更好地说,为什么他们在 setter 中引发属性更改事件(请参见下面的代码)。我们已经知道 ObservableCollection 在 add,update 完成时会自动引发,那么我们不需要再次引发。对吧?

请澄清我的疑问。

public class TheViewModel()
{
   private ObservableCollection<Camper> _campers;
   public ObservableCollection<Camper> Campers
   {
       get { return _campers; }
       set
       {
           if (Equals(_campers, value)) return;

           _campers = value;
           RaisePropertyChanged("Campers"); //Or however you implement it
       }
   }

【问题讨论】:

  • 新的露营者与添加或移除现有露营者不同。 Campers.Add 调用未设置。

标签: wpf


【解决方案1】:

如果您将 Campers 设置为指向一个新实例,那么 RaisePropertyChanged 将为您完成这项工作。否则,您将引用旧实例,并且视图将保持不同步。另一个解决方案是,每次将 Campers 设置为指向新集合时,再次为 DataGrid 或 ListView 或您使用的任何控件设置 ItemsSource。

确实,只要您从收藏中添加或删除项目,此方法就有效。总而言之,这就是区别,当你再次设置时

Campers = new ObservableCollection<Camper>();

您的 RaisePropertyChanged 将被触发。

代码更新:

XAML:

<Window x:Class="ObservablePropertyChanged.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <StackPanel>
        <ListView ItemsSource="{Binding items}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding}"/>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <Button Content="Change collection" Click="btnChangeCollection_Click"/>
    </StackPanel>
</Grid>

后面的代码:

public partial class MainWindow : Window
{
    public ObservableCollection<string> items { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        items = new ObservableCollection<string>();
        items.Add("One");
        items.Add("Two");
        this.DataContext = this;
    }

    private void btnChangeCollection_Click(object sender, RoutedEventArgs e)
    {
        items = new ObservableCollection<string>();
        items.Add("Three");
        items.Add("Four");
    }
}

由于我没有实现 INPC 接口,并且没有在项目集合上添加 PropertyChanged,因此单击按钮后,您将不会使用项目“三”和“四”更新视图。

这是完成此行为的另一种方法:

    public ObservableCollection<string> items
    {
        get { return (ObservableCollection<string>)GetValue(itemsProperty); }
        set { SetValue(itemsProperty, value); }
    }

    // Using a DependencyProperty as the backing store for items.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty itemsProperty =
        DependencyProperty.Register("items", typeof(ObservableCollection<string>), typeof(MainWindow), new UIPropertyMetadata(null));

使用此依赖属性,ListView 将保持同步。

【讨论】:

  • 我在我的视图中绑定了露营者,一旦我将项目添加到露营者,它会使用以下代码更新视图。注意:我已删除 RaisePropertyChanged("Campers") public class TheViewModel() { private ObservableCollection _campers;公共 ObservableCollection 露营者 { 获取;放;所以我的问题是如果可观察集合自动更新视图那么我们不需要使用 RaisePropertyChanged。
  • @shashank 如果没有 RaisePropertyChanged,如果您更改 Campers 指向的集合,您将不同步。
  • @shashank 有两个不同的东西。添加和删​​除项目或更改 Capmers 指向的整个集合。因此,无需从某个地方调用 RaisePropertyChanged 尝试 Camper = new ObservableCollection() 并开始添加项目。您的视图不会更新。
  • 我按照你说的试过了,效果很好。完美的。谢谢 。总结一下 1. 如果整个属性被替换为新值,那么 INotifyPropertyChanged 就会出现,我们需要在 setter 中引发事件。例如 Campers 被 ObservableCollection 的新实例替换。此外,这适用于任何数据类型的任何属性,如 int 、 string 等,但另一方面 2. 在可观察集合的情况下,如果您只是添加、删除同一实例中的项目(当然不替换为新实例)那么您不需要在 setter.Right 中引发事件吗?继续---
  • 续——现在,当我尝试使用 Campers[0].NAME = "Foo"; 更新 Camper 类的“名称”属性时Campers[0].NAME = "咕";它没有同时使用 1 和 2 更新我的视图。为什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多