在 Winform 中,为什么当我在一个数据源上调用 PropertyChanged 时所有绑定属性都会更新?
In Winform why ALL bound properties are updated when I call PropertyChanged on ONE data source?
我有两个按钮并将它们的 属性 绑定到数据对象的两个属性。
但是当我调用数据对象的 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。)
@Jimi 的方法 works.Simple 和 effective.I 将每个 属性 放入 shell class 并将数据绑定到 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"
。
我决定使用一个基础 class 来创建所有 shells.But 我真正的 DataClass
必须从其他 class 继承并且 C# 不支持 multi-inherit.So 我必须使用扩展名 class.
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");
它有点复杂,但效果很好。
我有两个按钮并将它们的 属性 绑定到数据对象的两个属性。
但是当我调用数据对象的 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。)
@Jimi 的方法 works.Simple 和 effective.I 将每个 属性 放入 shell class 并将数据绑定到 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"
。
我决定使用一个基础 class 来创建所有 shells.But 我真正的 DataClass
必须从其他 class 继承并且 C# 不支持 multi-inherit.So 我必须使用扩展名 class.
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");
它有点复杂,但效果很好。