c# - .NET WinForms INotifyPropertyChanged 在更改时更新所有绑定(bind)。更好的方法?

标签 c# .net winforms data-binding inotifypropertychanged

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

这似乎是荒谬的浪费,因为接口(interface)需要更改属性的名称。它导致我的应用程序出现大量时钟,因为某些属性 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));
        }
    }
}

最佳答案

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

另请查看这篇文章,尤其是这条评论(http://www.codeproject.com/Messages/2514032/How-Binding-watches-control-properties-i-e-how-doe.aspx),它准确解释了 propertychanged 事件是如何触发的,尽管它不会解决您的 getter 问题:http://www.codeproject.com/KB/database/databinding_tutorial.aspx?msg=2514032

探索的一个想法是延迟 getter 被调用。您可以通过使用绑定(bind)的 ControlUpdateMode 属性来实现这一点。当这个值设置为 Never 时,相应的控件在有变化时不会更新。但是,当您将该值切换回 OnPropertyChanged 时,将调用 PushData 方法,因此将访问 getter。因此,考虑到您的示例,此代码将暂时阻止文本框 2 更新:

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

关于c# - .NET WinForms INotifyPropertyChanged 在更改时更新所有绑定(bind)。更好的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2820447/

相关文章:

c# - Crystal 报表 |打印 |默认打印机

.net - 更改注册表项的 ACL,编辑值,然后将其改回

c# - 解决方案资源管理器上缺少 Visual Studio 2022 查看代码按钮

c# - 在 Windows 窗体 C# 应用程序的配置文件中设置值

c# - 如何为我的代码正确使用 "using"语句

c# - Unity 5.3 WeakReference 的非泛型类型错误

c# - 来自 C 背景,在 C# 中实现 const 引用数据表/结构的好方法是什么?

c# - 在 NUnit 中测试不可编译的代码

c# - 等到事件引发,然后继续代码

c# - ReSharper 包装测试结果堆栈跟踪?