.net - .NET 中的双向数据绑定(bind)不起作用,即使使用 INotifyPropertyChanged 对象也是如此

标签 .net winforms data-binding

我正在开发一个 Windows 窗体应用程序,这当然涉及到对象的数据绑定(bind)。

据我所知,双向数据绑定(bind)不能在 .NET 中开箱即用。

我的问题是我找不到关于实现它的一致信息:

  • 根据“.NET WinForms 简而言之”,我必须为每个属性创建一个名为 Changed 的​​事件,并在关联属性的 setter 中触发它。

  • 根据在线资源(包括 MSDN),我只需要在我的类中实现 INotifyPropertyChanged,并在所有 setter 中触发 PropertyChanged 事件,并传入属性名称。

但是,假设我有一个简单的 UI,其中文本框数据绑定(bind)到类的属性(实现上述方法之一),如果我在代码中设置数据绑定(bind)属性的值,UI 不会反射(reflect)更改,使用任一方法。

那么我在这里缺少什么?

编辑

我应该提到,INotifyPropertyChanged 不是在相关类的声明中实现的,而是通过动态代码生成实现的,大致相当于 DynamicProxy。我正在为该主题创建一个新问题,因为答案符合实际问题。

另一个编辑 INotifyPropertyChanged 已由代码生成工具正确实现,我已通过将代理对象的实例强制转换为 INotifyPropertyChanged 来检查这一点,并为该事件注册了一个处理程序,该事件确实会引发当属性的值改变时。

数据绑定(bind)的 UpdateMode 设置为 NotifyPropertyChanged,关联控件上的 CausesValidation 设置为 false。

所以伪代码如下所示:

class MyForm {
    MyClass localObj;
    BindingSource mySource = new BindingSource();

    MyForm(MyClass obj) {
        localObj = obj.CreateProxy() // Ensures localObj is a proxy instance
        mySource.Datasource = localObj // After this, UI is updated accordingly

        localObj.someProperty = "I changed the value" // Here, the NotifyPropertyChanged event does get fired, but the UI does not update. Hence my question...
        Console.WriteLine(localObj.someProperty) // Output is 'I changed the value'
    }

}

因此,更新 UI 的唯一方法是在 BindingSource 上调用 ResetBindings...这违背了双向绑定(bind)恕我直言的目的。

终于!!

问题来自于设计者。在设计时,我无法访问业务对象代理的真实类型,这是代理生成的运行时类型(这是功能性的,我对此部分没有任何疑问)。因此,设计者使用业务对象的已知数据类型而不是代理的数据类型(继承自 BO 的类)来初始化 BindingSource

因此,需要使用代理对象的运行时类型手动初始化数据源,以使双向绑定(bind)正常工作。

工作版本如下(伪C#):

class MyForm {
    Object localObj;
    BindingSource mySource;

    MyForm(MyClass obj) {
        localObj = obj.CreateProxy() // Ensures localObj is a proxy instance

        ((ISupportInitialize) mySource).BeginInit()
        mySource.Datasource = localObj.GetType()
        ((ISupportInitialize) mySource).EndInit()

        mySource.Datasource = localObj // After this, UI is updated accordingly

        localObj.someProperty = "I changed the value" // UI updates ! :)
    }
}

感谢大家的建议和帮助,你们救了我的命。我当时就用头撞墙了!

最佳答案

我会在加载表单之前检查动态代码生成是否确实添加了 INotifyChanged。然后我会检查您通过代码更改的对象的 public 属性实际上是否与当前在屏幕上显示的对象相同(它是一个列表吗?还是单个对象?)。确保数据绑定(bind)设置为 OnPropertyChanged 而不是 OnValidation。然后我会检查它是否以相反的方式工作:编辑数据绑定(bind)文本框值并查看在您选择另一个控件后该对象是否获得新值。使用这样的代码(伪代码)更改属性时要小心。

ctor(MyClass objParm){
  this.localobj = objParm;
  bindingsource1.datasource = objParm; // or this.localobj
}
SomeMethod(){
  this.localobj = new MyClass();
  this.localobj.MyProperty = 'new value';
}

这将不起作用,除非您更改为

SomeMethod(){
  this.localobj = new MyClass();
  this.localobj.MyProperty = 'new value';
  bindingsource1.datasource = this.localobj
}

更新:
您说数据绑定(bind)不能开箱即用,但我可以向您保证它可以。看到您提供的代码后,我怀疑它与动态代理生成/CreateProxy() 方法有关。由于 ResetBindings 有效,这可能与 CreateProxy 返回与 MyClass 不同的类有关。数据绑定(bind)对于类型非常挑剔。例如。如果您使用接口(interface)(例如 List)作为数据源,数据绑定(bind)可能会出错,因为它们不是相同的类型。这就是为什么您需要使用 new BindingList() 作为数据源。只是向您提供一些可能为您指明正确方向的背景信息。在您的情况下,元数据可能会由于动态代码生成而发生变化,请查看有关 ResetBindings() 的 msdn 文档。作为测试,请尝试以下操作:

mySource.Datasource = new BindingList<MyClass>(new List<MyClass>(){this.localobj});

关于.net - .NET 中的双向数据绑定(bind)不起作用,即使使用 INotifyPropertyChanged 对象也是如此,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9911757/

相关文章:

WPF datagrid 隐藏列与动态数据源

javascript - 如何在 Angularjs 中创建过滤器?

c# - 如何使 .NET COM 对象成为单元线程?

c# - 使用 .NET 在 sAMAccountName 中创建超过 20 个字符的用户时出错

c# - Process.WaitForExit() 异步

winforms - SharpGL - 用网格绘制球体并为每个球体附加颜色

c# WPF datagrid数据绑定(bind)错误

c# - 来自数据库或代码的 DropDownListFor 枚举的 MVC4 最佳实践

.NET 4.5 ZipFile 类未生成一致的文件

c# - 在 datetimepicker winform c# 中禁用一些日期