Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何传播集合中对象的属性更改通知_C#_Event Handling_Inotifypropertychanged_Windows Forms Designer - Fatal编程技术网

C# 如何传播集合中对象的属性更改通知

C# 如何传播集合中对象的属性更改通知,c#,event-handling,inotifypropertychanged,windows-forms-designer,C#,Event Handling,Inotifypropertychanged,Windows Forms Designer,假设我有这样的课 public class R { protected string name; protected List<S> listOfObjectS; } public class S { private string name, ID; private A objectA; } public class A { private string name; private int count; } 公共类R { 受保护的

假设我有这样的课

public class R
{
    protected string name;
    protected List<S> listOfObjectS;
}

public class S
{
    private string name, ID;
    private A objectA;
}

public class A
{
    private string name;
    private int count;
}
公共类R
{
受保护的字符串名称;
受保护的对象列表;
}
公共类
{
私有字符串名称,ID;
私人反对;
}
公共A类
{
私有字符串名称;
私人整数计数;
}
如果用户有两个打开的视图,一个显示
R
的实例,另一个允许用户修改
a
的实例,我需要在用户更改
a
的任何实例时更改
R
的视图


如果用户更改了
a
实例的属性,传播该更改(通过
S
实例)的最佳方式是什么因此,
R
的所有实例都会显示
A

编辑的新状态:彻底检查此答案,使其更具体地针对问题,因为标记显示您已经知道

您需要在类
A
和类
S
中实现
INotifyPropertyChanged
。使
objectA
只能通过一个属性设置,该属性在
a
中更改属性时,将在S上引发
PropertyChanged
事件。例如:

public class A : INotifyPropertyChanged
{
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value; OnPropertyChanged("Name"); }
    }

    private int count;

    public int Count
    {
        get { return count; } 
        set { count = value; OnPropertyChanged("Count"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
public class R
{
    protected string name;
    protected System.Collections.ObjectModel.ObservableCollection<S> ListOfObjectS { get; private set; }

    public R()
    {
        // Use ObservableCollection instead.
        ListOfObjectS = new ObservableCollection<S>();

        // Subscribe to all changes to the collection.
        ListOfObjectS.CollectionChanged += listOfObjectS_CollectionChanged;
    }

    void listOfObjectS_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            // When items are removed, unsubscribe from property change notifications.
            var oldItems = (e.OldItems ?? new INotifyPropertyChanged[0]).OfType<INotifyPropertyChanged>();
            foreach (var item in oldItems)
                item.PropertyChanged -= item_PropertyChanged;
        }

        // When item(s) are added, subscribe to property notifications.
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            var newItems = (e.NewItems ?? new INotifyPropertyChanged[0]).OfType<INotifyPropertyChanged>();
            foreach (var item in newItems)
                item.PropertyChanged += item_PropertyChanged;
        }

        // NOTE: I'm not handling NotifyCollectionChangedAction.Reset.
        // You'll want to look into when this event is raised and handle it
        // in a special fashion.
    }

    void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName.StartsWith("ObjectA."))
        {
            // Refresh any dependent views, forms, controls, whatever...
        }
    }
}
。。。和类
S

public class S : INotifyPropertyChanged
{
    private string name, ID;
    private A objectA;

    public A ObjectA
    {
        get { return objectA; }
        set
        {
            var old = objectA;
            objectA = value;

            // Remove the event subscription from the old instance.
            if (old != null) old.PropertyChanged -= objectA_PropertyChanged;

            // Add the event subscription to the new instance.
            if (objectA != null) objectA.PropertyChanged += objectA_PropertyChanged;

            OnPropertyChanged("ObjectA");
        }
    }

    void objectA_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        // Propagate the change to any listeners. Prefix with ObjectA so listeners can tell the difference.
        OnPropertyChanged("ObjectA." + e.PropertyName);
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
对于类
R
,使用
ObservableCollection
而不是
List
,订阅其
CollectionChanged
事件,并监视对象何时添加或删除到
对象列表中。添加后,订阅
S
PropertyChanged
事件。然后更新了
R
的视图。例如:

public class A : INotifyPropertyChanged
{
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value; OnPropertyChanged("Name"); }
    }

    private int count;

    public int Count
    {
        get { return count; } 
        set { count = value; OnPropertyChanged("Count"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
public class R
{
    protected string name;
    protected System.Collections.ObjectModel.ObservableCollection<S> ListOfObjectS { get; private set; }

    public R()
    {
        // Use ObservableCollection instead.
        ListOfObjectS = new ObservableCollection<S>();

        // Subscribe to all changes to the collection.
        ListOfObjectS.CollectionChanged += listOfObjectS_CollectionChanged;
    }

    void listOfObjectS_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            // When items are removed, unsubscribe from property change notifications.
            var oldItems = (e.OldItems ?? new INotifyPropertyChanged[0]).OfType<INotifyPropertyChanged>();
            foreach (var item in oldItems)
                item.PropertyChanged -= item_PropertyChanged;
        }

        // When item(s) are added, subscribe to property notifications.
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            var newItems = (e.NewItems ?? new INotifyPropertyChanged[0]).OfType<INotifyPropertyChanged>();
            foreach (var item in newItems)
                item.PropertyChanged += item_PropertyChanged;
        }

        // NOTE: I'm not handling NotifyCollectionChangedAction.Reset.
        // You'll want to look into when this event is raised and handle it
        // in a special fashion.
    }

    void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName.StartsWith("ObjectA."))
        {
            // Refresh any dependent views, forms, controls, whatever...
        }
    }
}
公共类R
{
受保护的字符串名称;
受保护的System.Collections.ObjectModel.ObservableCollection列表对象{get;private set;}
公共资源(
{
//改用ObservableCollection。
ListOfObjectS=新的ObservableCollection();
//订阅对集合的所有更改。
ListOfObjectS.CollectionChanged+=ListOfObjectS\u CollectionChanged;
}
无效对象列表\u CollectionChanged(对象发送方,System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if(e.Action==NotifyCollectionChangedAction.Remove)
{
//删除项目后,取消订阅属性更改通知。
var oldItems=(e.oldItems??new INotifyPropertyChanged[0])of type();
foreach(旧项目中的var项目)
item.PropertyChanged-=item_PropertyChanged;
}
//添加项目后,订阅属性通知。
if(e.Action==NotifyCollectionChangedAction.Add)
{
var newItems=(e.newItems??new INotifyPropertyChanged[0])of type();
foreach(newItems中的var项)
item.PropertyChanged+=item_PropertyChanged;
}
//注意:我没有处理NotifyCollectionChangedAction.Reset。
//您需要了解何时引发此事件并处理它
//以一种特殊的方式。
}
无效项\u PropertyChanged(对象发送方,PropertyChangedEventArgs e)
{
if(e.PropertyName.StartsWith(“ObjectA”))
{
//刷新任何相关视图、窗体、控件等。。。
}
}
}

假设您有一个表单1,在该表单中,您使用类R的实例来显示来自类a的实例列表。然后按“编辑”并将该类a的实例从类R实例发送到新表单

这将是对R实例中包含的对象的引用,因此将在form2中更新。您唯一需要做的就是刷新form1列表中类A的实例


解释:当您使用类的对象实例调用窗体或方法时,这将创建引用,而不是克隆,因此可以从第二个窗体2进行更新。

一个nit,并不是所有对setter的调用都需要触发
OnPropertyChanged
,通常您需要执行
object.Equals(backingMember,value)
检查(因为您没有覆盖
Equals(object)
这将是一个引用相等性检查,在这种情况下可以),看看属性是否真的被更改,然后再通知任何订阅者这个事实。@Scott同意,特别是因为重新绘制UI太慢了。不过,我可能不会更新示例代码,因为它已经非常冗长,而且每增加一行都会使其更难理解。在某些情况下,设置属性(即使值没有更改)可能会导致刷新。不完全是它的用途,但我以前见过。就我个人而言,我不会使用
Object.Equals
,因为我们知道类型,所以
EqualityComparer.Default.Equals(backingValue,value)
将是更好的选择。