GVKun编程网logo

ObservableCollection 没有注意到其中的项目何时更改(即使使用 INotifyPropertyChanged)

10

如果您想了解ObservableCollection没有注意到其中的项目何时更改的相关知识,那么本文是一篇不可错过的文章,我们将对即使使用INotifyPropertyChanged进行全面详尽的解释

如果您想了解ObservableCollection 没有注意到其中的项目何时更改的相关知识,那么本文是一篇不可错过的文章,我们将对即使使用 INotifyPropertyChanged进行全面详尽的解释,并且为您提供关于.net – Observable Collections Collection已更改、C# INotifyPropertyChanged 实现、c# – INotifyPropertyChanged和ObservableCollection WPF、c# – WCF DataContracts中的INotifyPropertyChanged的有价值的信息。

本文目录一览:

ObservableCollection 没有注意到其中的项目何时更改(即使使用 INotifyPropertyChanged)

ObservableCollection 没有注意到其中的项目何时更改(即使使用 INotifyPropertyChanged)

有谁知道为什么这段代码不起作用:

public class CollectionViewModel : ViewModelBase {      public ObservableCollection<EntityViewModel> ContentList    {        get { return _contentList; }        set         {             _contentList = value;             RaisePropertyChanged("ContentList");             //I want to be notified here when something changes..?            //debugger doesn''t stop here when IsRowChecked is toggled        }     }}public class EntityViewModel : ViewModelBase{    private bool _isRowChecked;    public bool IsRowChecked    {        get { return _isRowChecked; }        set { _isRowChecked = value; RaisePropertyChanged("IsRowChecked"); }    }}

ViewModelBase包含RaisePropertyChanged等的所有内容,并且它适用于除此问题之外的所有其他内容..

答案1

小编典典

当您更改集合内的值时,不会调用 ContentList 的 Set
方法,而是应该注意CollectionChanged事件的触发。

public class CollectionViewModel : ViewModelBase{              public ObservableCollection<EntityViewModel> ContentList    {        get { return _contentList; }    }    public CollectionViewModel()    {         _contentList = new ObservableCollection<EntityViewModel>();         _contentList.CollectionChanged += ContentCollectionChanged;    }    public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)    {        //This will get called when the collection is changed    }}

好的,这是我今天两次被 MSDN 文档错误所困扰。在我给你的链接中,它说:

在添加、删除、更改、移动项目或刷新整个列表时发生。

但它实际上 不会 在更改项目时触发。我想你需要一个更暴力的方法:

public class CollectionViewModel : ViewModelBase{              public ObservableCollection<EntityViewModel> ContentList    {        get { return _contentList; }    }    public CollectionViewModel()    {         _contentList = new ObservableCollection<EntityViewModel>();         _contentList.CollectionChanged += ContentCollectionChanged;    }    public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)    {        if (e.Action == NotifyCollectionChangedAction.Remove)        {            foreach(EntityViewModel item in e.OldItems)            {                //Removed items                item.PropertyChanged -= EntityViewModelPropertyChanged;            }        }        else if (e.Action == NotifyCollectionChangedAction.Add)        {            foreach(EntityViewModel item in e.NewItems)            {                //Added items                item.PropertyChanged += EntityViewModelPropertyChanged;            }             }           }    public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)    {        //This will get called when the property of an object inside the collection changes    }}

如果你需要这个很多,你可能想要子类化你自己的子类ObservableCollectionCollectionChanged当成员PropertyChanged自动触发其事件时触发事件(就像它在文档中所说的那样......)

.net – Observable Collections Collection已更改

.net – Observable Collections Collection已更改

快速观察可观察的集合.我一直在玩Silverlight中的这些东西做一些有约束力的东西,你有什么.看起来像CollectionChanged事件在从集合中删除或添加时会触发.当我在集合中的一个类上更改属性时,我想要触发一些东西. collection属性本身已经有了RaisePropertyChanged.我是否需要对类型类本身做一些特殊操作?所以,如果我有这个:

ObservabelCollection<Person> personcollection... and if I change a property like:

Person p = personcollection.where(e => e.FirstName == "Joey").FirstOrDefault();
if (p != null) { p.FirstName = "Joe"; }

我希望在UI中发生一些事情,但没有任何改变.

任何帮助将不胜感激.

大卫

解决方法

我看到你正在尝试做什么但是如果我正确的Observable Collection只会在它的集合中的项目发生变化时引发INotifyCollectionChanged事件.这将触发UI中的更改.

它并不关心它的集合中某个对象的属性是否发生变化.您需要在这些对象的属性上实现INotifyPropertyChanged接口以触发对UI的更改.

我读了here,给了我一些有用的见解.虽然它针对WPF,但大多数仍然适用,因为Silverlight本质上是WPF的一个子集.

以及这篇MSDN文章,其中指出:

In particular,if you are using OneWay or TwoWay (for example,you want your UI to update when the source properties change dynamically),you must implement a suitable property changed notification mechanism 
 such as the INotifyPropertyChanged interface.

C# INotifyPropertyChanged 实现

C# INotifyPropertyChanged 实现

INotifyPropertyChanged:

该接口包含一个事件, 针对属性发生变更时, 执行该事件发生。

//
    // 摘要:
    //     通知客户端属性值已更改。
    public interface INotifyPropertyChanged
    {
        //
        // 摘要:
        //     在属性值更改时发生。
        event PropertyChangedEventHandler PropertyChanged;
    }

接下来, 用一个简单的示例说明其简单使用方法(大部分常用的做法演示):

1.定义一个ViewModelBase 继承INotifyPropertyChanged 接口, 添加一个虚函数用于继承子类的属性进行更改通知

2.MainViewModel中两个属性, Code,Name 进行了Set更改时候的调用通知,

     public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }


    public class MainViewModel : ViewModelBase
    {
        private string name;
        private string code;

        public string Name
        {
            get { return name; }
            set { name = value; OnPropertyChanged("Name"); }
        }

        public string Code
        {
            get { return code; }
            set { code = value; OnPropertyChanged("Code"); }
        }
    }

正如上面的代码, 应该注意到了, 每个属性调用OnPropertyChanged的时候, 都需要传一个自己的属性名, 这样是不是很多余?对, 很多余。

 

改造

1.看到有些文章给基类的参数修改为表达式树, 这样实现的时候,传递一个Lambda表达式, 我觉得这是不治标不治本吗?如下: 

说明: 原来直接传递一个固定的string类型实参,  不说换成lambda的性能问题, 同样带来的问题你还是固定的需要去书写这个参数。 不建议这么做!

 

CallerMemberName

 该类继承与 Attribute, 不难看出, 该类属于定义在方法和属性上的一种特效类, 实现该特性允许获取方法调用方的方法或属性名称

    //
    // 摘要:
    //     允许获取方法调用方的方法或属性名称。
    [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
    public sealed class CallerMemberNameAttribute : Attribute
    {
        //
        // 摘要:
        //     初始化 System.Runtime.CompilerServices.CallerMemberNameAttribute 类的新实例。
        public CallerMemberNameAttribute();
    }

 改造ViewModelBase:

 

改造之后, 是不是发现明显区别:

不用传递参数, 不用书写lambda表达式, 也不用担心其传递的参数安全, 直接根据读取属性名!

c# – INotifyPropertyChanged和ObservableCollection WPF

c# – INotifyPropertyChanged和ObservableCollection WPF

现在我有一个只显示一个月的日历(我通过的月份).我试图让用户从comboBox中选择月份和年份并更新日历.我使用observablecollection绑定,我很熟悉.我不知道INotifyPropertyChanged如何工作.我以前从未使用过它.非常感谢任何帮助或建议.这是我到目前为止:

public class Schedule : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void Update(int propertyName)
    {
        if (propertyName != null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                 handler.Invoke(this,new PropertyChangedEventArgs(propertyName.ToString()));
        }
    }


   // public void UpdateCal(PropertyChangedEventArgs e)
   // {
    //    if (PropertyChanged != null)
    //        PropertyChanged(this,e);
  //  } 
    public string MonthWeek { get; set; }
    public string Year { get; set; }
    public string Month { get; set; }
    public string day { get; set; }
    public string WeekOfYear { get; set; }
    public string dayofweek { get; set; }

   // public string month {
    //    get {return Month; }
    //    set
    //    {
     //       UpdateCal(new PropertyChangedEventArgs("month"));
      //  }
   // }
    public int WeekNo { get; set; }
    public int WeekDay { get; set; }
    public DateTime Date { get; set; }
 }

—这是另一个类,它确定了每个日期在网格上的位置—-

public SchedulePage(MainWindow parentForm)
    {
        InitializeComponent();

        pick = Convert.ToInt32(comboMonth.SelectedItem) + 1;
        _parentForm = parentForm;
        // DateTime date = new DateTime(year,month,day);
        var t = new List<Schedule>();
        DateTime curr = DateTime.Now;
      //  comboMonth.Items.Add(curr.Month);
        DateTime newcurr = new DateTime(2011,pick,1);
     //   pickdate = datePickercal.SelectedDate;
      //  DateTime newcurr = new DateTime(curr.Year,curr.Month,1);
        var cal = System.Globalization.DateTimeFormatInfo.CurrentInfo.Calendar;
        var ms = cal.GetWeekOfYear(new DateTime(newcurr.Year,newcurr.Month,1),System.Globalization.CalendarWeekRule.FirstDay,System.DayOfWeek.Sunday);
        for (var i = 1; newcurr.Month == pick; newcurr = newcurr.AddDays(1))
        {
            var sched = new Schedule();
            var month_week = (newcurr.Day / 7) ;
            sched.MonthWeek = newcurr.GetWeekOfMonth().ToString();
            sched.Month = newcurr.Month.ToString();
            sched.Year = newcurr.Year.ToString();
            sched.day = newcurr.Day.ToString();
            sched.WeekOfYear = cal.GetWeekOfYear(newcurr,DayOfWeek.Sunday).ToString();
            sched.dayofweek = newcurr.DayOfWeek.ToString();
            t.Add(sched);

                _parentForm.bindings.schedule.Add(new Schedule { WeekNo = newcurr.GetWeekOfMonth()-1,WeekDay = (int)newcurr.DayOfWeek,day = newcurr.Day.ToString() });

        }
        lblDate.Content = (newcurr.Month -1) + "/" + newcurr.Year;

         DataContext = _parentForm.Bindings;

—这个类使观察收集—–

public partial class BindingCamper 
{  // This class assist in binding campers from listview to the textBoxes on the camperspage
    public ObservableCollection<Camper> Campers { get; set; }
    public ObservableCollection<Staff> StaffMembers { get; set; }
    public ObservableCollection<Schedule> schedule { get; set; }
    public BindingCamper()
    {
        Campers = new ObservableCollection<Camper>();
      StaffMembers = new ObservableCollection<Staff>();
      schedule = new ObservableCollection<Schedule>();
    }

解决方法

这是您通常实现INotifyPropertyChanged的方式:

public class Schedule : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this,new PropertyChangedEventArgs(propertyName));
    }

    private string _monthWeek;
    public string MonthWeek
    {
        get { return _monthWeek; }
        set
        {
            if (value != _monthWeek)
            {
                _monthWeek = value;
                OnPropertyChanged("MonthWeek");
            }
        }
    }

    // And so on for other properties...

}

基本上,每次更新属性时都需要触发PropertyChanged事件,因此每个setter都必须调用OnPropertyChanged.请注意,您无法使用自动实现的属性执行此操作,因为您需要在setter中添加自定义逻辑.

c# – WCF DataContracts中的INotifyPropertyChanged

c# – WCF DataContracts中的INotifyPropertyChanged

我正在制作一些WCF服务,一些消费者是Prism Apps.

为了避免将DataContract类复制到客户端类,他们希望合同支持INotifyPropertyChanged.

但是,我有一些客户端是MVC3客户端.

添加INotifyPropertyChanged支持数据合同会搞砸他们吗?

另外,我打算让我的DataContracts也成为我的Entity Framework数据库连接的POCO对象.将INotifyPropertyChanged搞砸了吗?

或者INotifyPropertyChanged只是一个WPF的东西,其他的应用程序将不关心它?

解决方法

Or is INotifyPropertyChanged just a WPF thing and the other apps won’t care about it?

INotifyPropertyChanged只是一个可以在您的实体上实现的界面,而不会弄乱任何东西.它主要用于WPF和Silverlight,它不会对不使用它的其他技术产生影响.因此,在WCF数据协定上实现它不应该有任何问题.虽然请注意,当您从此WCF服务生成强类型客户端代理(使用svcutil.exe或添加服务引用)时,生成的实体将不会实现此接口.他们将是POCO.

今天关于ObservableCollection 没有注意到其中的项目何时更改即使使用 INotifyPropertyChanged的分享就到这里,希望大家有所收获,若想了解更多关于.net – Observable Collections Collection已更改、C# INotifyPropertyChanged 实现、c# – INotifyPropertyChanged和ObservableCollection WPF、c# – WCF DataContracts中的INotifyPropertyChanged等相关知识,可以在本站进行查询。

本文标签: