.NET WinForms INotifyPropertyChanged在更改一个绑定时更新所有绑定.更好的方法?

Dav*_*ing 24 .net c# data-binding inotifypropertychanged winforms

在Windows窗体应用程序中,触发INotifyPropertyChanged的属性更改将导致窗体从绑定对象读取每个属性,而不仅仅是属性已更改.(参见下面的示例代码)

这似乎是荒谬的浪费,因为界面需要更改属性的名称.它在我的应用程序中导致大量计时,因为某些属性getter需要执行计算.

如果没有更好的方法,我可能需要在我的getter中实现某种逻辑来丢弃不必要的读取.

我错过了什么吗?有没有更好的办法?不要说使用不同的演示技术 - 我在Windows Mobile上这样做(虽然行为也发生在完整的框架上).

这里有一些玩具代码来演示这个问题.单击该按钮将导致即使一个属性已更改,也会填充两个文本框.

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace Example
{
public class ExView : Form
{
    private Presenter _presenter = new Presenter();
    public ExView()
    {
        this.MinimizeBox = false;

        TextBox txt1 = new TextBox();
        txt1.Parent = this;
        txt1.Location = new Point(1, 1);
        txt1.Width = this.ClientSize.Width - 10;
        txt1.DataBindings.Add("Text", _presenter, "SomeText1");

        TextBox txt2 = new TextBox();
        txt2.Parent = this;
        txt2.Location = new Point(1, 40);
        txt2.Width = this.ClientSize.Width - 10;
        txt2.DataBindings.Add("Text", _presenter, "SomeText2");

        Button but = new Button();
        but.Parent = this;
        but.Location = new Point(1, 80);
        but.Click +=new EventHandler(but_Click);
    }

    void but_Click(object sender, EventArgs e)
    {
        _presenter.SomeText1 = "some text 1";
    }
}

public class Presenter : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    private string _SomeText1 = string.Empty;
    public string SomeText1
    {
        get
        {
            return _SomeText1;
        }
        set
        {
            _SomeText1 = value;
            _SomeText2 = value; // <-- To demonstrate that both properties are read
            OnPropertyChanged("SomeText1");
        }
    }

    private string _SomeText2 = string.Empty;
    public string SomeText2
    {
        get
        {
            return _SomeText2;
        }
        set
        {
            _SomeText2 = value;
            OnPropertyChanged("SomeText2");
        }
    }

    private void OnPropertyChanged(string PropertyName)
    {
        PropertyChangedEventHandler temp = PropertyChanged;
        if (temp != null)
        {
            temp(this, new PropertyChangedEventArgs(PropertyName));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

}

anc*_*dra 15

触发事件时读取所有属性的原因在于触发ProperyChanged事件时在绑定对象上调用的PushData方法.如果查看堆栈跟踪,您会注意到内部对象BindToObject的PropValueChanged方法被调用,而该方法又调用BindingManager上的Oncurrentchanged事件.绑定机制会跟踪当前项目的更改,但不会进行更细微的区分."罪魁祸首"PushData方法调用属性上的getter(使用反射器查看代码).所以没有办法绕过它.话虽如此,根据经验,在get和set访问器中,不建议进行繁重的处理,为此使用单独的get和set方法(如果可能)

另外看看这篇文章,特别是这篇评论(http://www.codeproject.com/Messages/2514032/How-Binding-watches-control-properties-ie-how-doe.aspx),这完全可以解释如何解决propertychanged事件,虽然它不会解决你的getter问题:http://www.codeproject.com/KB/database/databinding_tutorial.aspx? msg = 2514032

探索的想法是延迟被调用的吸气剂.您可以通过使用绑定的ControlUpdateMode属性来实现此目的.当此值设置为"从不"时,相应的控件将在更改时不会更新.但是,当您将值切换回OnPropertyChanged时,将调用PushData方法,因此将访问getter.因此,考虑到您的示例,此代码将暂时阻止文本框2更新:

void but_Click(object sender, EventArgs e)
        {                   
            txt2.DataBindings[0].ControlUpdateMode = ControlUpdateMode.Never;
            _presenter.SomeText1 = "some text 1";
        }
Run Code Online (Sandbox Code Playgroud)