繁体   English   中英

在 Winform 中,为什么当我在一个数据源上调用 PropertyChanged 时所有绑定的属性都会更新?

[英]In Winform why ALL bound properties are updated when I call PropertyChanged on ONE data source?

我有两个按钮并将它们的属性绑定到数据 object 的两个属性。 但是当我调用数据 object 的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")) )时, ButtonAButtonB显示新文本。

  • 如果我调用PropertyChanged(this, new PropertyChangedEventArgs("DataA")) ,两个按钮都会更新。

  • 如果我不更改DataA / DataB的值而只是调用PropertyChanged(this, new PropertyChangedEventArgs("DataB")) ,仍然会更新两个按钮(可以通过断点调试注意到)。

  • 如果我调用PropertyChanged(this, new PropertyChangedEventArgs("QQQ")) ,则不会更新任何按钮。

PropertyChangedEventArgs有一个名为propertyName的属性,我认为它用于指定一个要通知的属性,但事实并非如此。

在我的真实代码中, DataBDataA更频繁地更改。 我不想每次更改DataB时都更新ButtonA ,这需要太多时间。

问题:为什么会发生这种情况? 更改数据源属性时,如何仅更新真正连接到它的属性?

(所有代码都是Windows上的.Net Framework 4.7.1。)

@Jimi 的方法有效。简单有效。我将每个属性放在 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"

I decide to use a base class to create all shells.But my real DataClass must inherit from other class and C# don't support multi-inherit.So I have to use a extension 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");

这有点复杂,但效果很好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM