在 Winform 中,为啥当我在一个数据源上调用 PropertyChanged 时所有绑定的属性都会更新?
Posted
技术标签:
【中文标题】在 Winform 中,为啥当我在一个数据源上调用 PropertyChanged 时所有绑定的属性都会更新?【英文标题】:In Winform why ALL bound properties are updated when I call PropertyChanged on ONE data source?在 Winform 中,为什么当我在一个数据源上调用 PropertyChanged 时所有绑定的属性都会更新? 【发布时间】:2021-03-10 08:17:21 【问题描述】:我有两个按钮并将它们的属性绑定到数据对象的两个属性。
但是当我调用数据对象的PropertyChanged
时,每个属性都会更新。
public partial class Form1 : Form
private DataClass data = new DataClass();
public Form1()
InitializeComponent();
ButtonA.DataBindings.Add("Text", data, "DataA");
ButtonB.DataBindings.Add("Text", data, "DataB");
ButtonB.Click += new EventHandler(OnButtonBClicked);
private void OnButtonBClicked(object sender, EventArgs e)
data.DataA += "1";
data.DataB += "1";
data.Notify("DataB");
public class DataClass : INotifyPropertyChanged
public string DataA get; set;
public string DataB get; set;
public event PropertyChangedEventHandler PropertyChanged;
public DataClass()
public void Notify(string property_name)
PropertyChanged(this, new PropertyChangedEventArgs(property_name));
当我按ButtonB
(这意味着我呼叫PropertyChanged(this, new PropertyChangedEventArgs("DataB"))
)时,ButtonA
和ButtonB
都会显示新文本。
如果我调用PropertyChanged(this, new PropertyChangedEventArgs("DataA"))
,两个按钮都会更新。
如果我不更改DataA
/ DataB
的值而只是调用PropertyChanged(this, new PropertyChangedEventArgs("DataB"))
,仍然会更新两个按钮(可以通过断点调试注意到)。
如果我调用PropertyChanged(this, new PropertyChangedEventArgs("QQQ"))
,则不会更新任何按钮。
PropertyChangedEventArgs
有一个名为propertyName
的属性,我以为它是用来指定一个要通知的属性,但它没有。
在我的真实代码中,DataB
的变化比DataA
更频繁。我不想每次更改DataB
都更新ButtonA
,这太耗时了。
问题:为什么会发生这种情况?当数据源属性发生变化时,我如何才能只更新真正连接到它的属性?
(所有代码在 Windows 上都是 .Net Framework 4.7.1。)
【问题讨论】:
你愿意修改你的类结构来实现复杂的数据绑定吗?在这种情况下,您的string
属性将更改为类对象。简单绑定会导致对所有绑定属性调用 getter,否则所有设置为新值的属性都会在 Binding 对象中引发更改事件。
@Jimi :哦,是的。这是一个好方法。我将每个属性都放在一个对象中,然后一切都按预期工作。thx。
【参考方案1】:
@Jimi的方法行得通。简单有效。我把每个属性都放在一个shell类中,并给shell绑定数据:
public class MyProperty<T>: INotifyPropertyChanged
public T Content get; set;
public event PropertyChangedEventHandler PropertyChanged;
public MyProperty(T _content)
Content = _content;
public void Notify()
PropertyChanged(this, new PropertyChangedEventArgs("Content"));
public class DataClass
public MyProperty<string> DataA = new MyProperty<string>("");
public MyProperty<string> DataB = new MyProperty<string>("");
public DataClass()
但是这样我必须在每个地方都使用DataA.Content+="1"
而不是DataA+="1"
。
我决定使用基类来创建所有的shell。但是我真正的DataClass
必须从其他类继承,而C#不支持多继承。所以我必须使用扩展类。
public class BindHandle<T> : INotifyPropertyChanged
public T Content get return (T)parent.GetType().GetProperty(prop_name).GetValue(parent);
private object parent;
private string prop_name;
public event PropertyChangedEventHandler PropertyChanged;
public BindHandle(object _parent, string _prop_name)
parent = _parent;
prop_name = _prop_name;
public void NotifyChange()
PropertyChanged(this, new PropertyChangedEventArgs("Content"));
public interface IBindHandleProvider
BindHandleProvider provider get; set;
public class BindHandleProvider
private Dictionary<string, object> handle_map = new Dictionary<string, object>();
public BindHandle<T> GetBindHandle<T>(object obj,string property_name)
if (!handle_map.ContainsKey(property_name))
handle_map.Add(property_name, new BindHandle<T>(obj, property_name));
return (BindHandle<T>)handle_map[property_name];
public void NotifyChange<T>(string property_name)
if (handle_map.ContainsKey(property_name))
((BindHandle<T>)handle_map[property_name]).NotifyChange();
public static class BindHandleProviderExtension
public static void NotifyChange<T>(this IBindHandleProvider obj, string property_name)
obj.provider.NotifyChange<T>(property_name);
public static BindHandle<T> GetBindHandle<T>(this IBindHandleProvider obj, string property_name)
return obj.provider.GetBindHandle<T>(obj,property_name);
public class DataClass:IBindHandleProvider
public BindHandleProvider provider get; set; = new BindHandleProvider();
public string DataA get; set; = "";
public string DataB get; set; = "";
public DataClass()
然后像这样绑定
ButtonA.DataBindings.Add("Text", data.GetBindHandle<string>("DataA"), "Content");
并通知喜欢
data.NotifyChange<string>("DataB");
这有点复杂,但效果很好。
【讨论】:
以上是关于在 Winform 中,为啥当我在一个数据源上调用 PropertyChanged 时所有绑定的属性都会更新?的主要内容,如果未能解决你的问题,请参考以下文章
成功完成初始自动完成后,如何在 WinForm 文本框上重新启动自动完成?
为啥当我在 grails 上删除一对多关系上的父级时,会在子级上调用 beforeInsert 事件?
为啥当我在 mysql 中调用 STORED PROCEDURE 时 pdo->lastInsertId() 返回 0?