【问题标题】:Data Binding doesn't work when I assign a new object instance to the bound variable当我将新对象实例分配给绑定变量时,数据绑定不起作用
【发布时间】:2017-02-10 13:13:59
【问题描述】:

我有一个对象,我已使用 C# WinForms(针对 .NET 4.5.2)绑定到表单上的控件。我已经实现了INotifyPropertyChanged,当我修改这个对象的一个​​属性时,它会按预期更新表单的控件。但是,当我将此对象的实例更改为新实例时,它将不再更新控件,即使我尝试修改特定的属性也是如此。

class User : INotifyPropertyChanged
{
    string _name = "";

    public string Name
    {
        get { return _name; }
        set { _name = value; OnPropertyChanged("Name"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string property)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
    }

    public User() { }

    public User(string name)
    {
        Name = name;
    }

    public User(User otherUser)
    {
        Name = otherUser.Name;
    }
}

在我的表格上

User currentUser = new User("Example Name");
lblName.DataBindings.Add("Text", currentUser, "Name");

正确更新。我可以使用currentUser.Name = "Blahblah"; 更改名称,它工作正常。当我尝试拨打currentUser = new User("New Name"); 时,无论我做什么都不会再更新。

据我了解,对象的特定实例是控件所绑定的对象。我的主要目标是不必手动检查较大对象的每个属性,并在每次我想更改实例时手动更改所有内容。

我的问题:有没有办法在不删除控件绑定的情况下更改对象的实例?

【问题讨论】:

    标签: c# .net winforms data-binding


    【解决方案1】:

    要获得所需的行为,您不应像当前那样直接绑定到具体实例:

    lblName.DataBindings.Add("Text", currentUser, "Name");
    

    相反,您需要一些中介。最简单的方法是为此目的使用BindingSource 组件。

    在表单中添加BindingSource 字段:

    private BindingSource dataSource;
    

    然后对其进行初始化并将控件绑定一次(通常以Load事件的形式):

    dataSource = new BindingSource { DataSource = typeof(User) };
    lblName.DataBindings.Add("Text", dataSource, "Name");
    // ...
    

    现在,只要您想绑定到 User 实例,只需将其分配给 BindingSource 的 DataSource 属性即可:

    首字母:

    dataSource.DataSource = new User("Example Name");
    

    稍后:

    dataSource.DataSource = new User("New Name"); 
    

    【讨论】:

      【解决方案2】:

      Ivan 向您展示了如何解决问题。在此答案中,我将尝试向您展示问题所在以及为什么会这样。

      简答

      您的标签绑定到一个对象而不是变量。变量就像指向对象的指针。因此,替换变量不会对您的标签用作数据源的对象产生任何影响。只是变量指向新对象。但是您的标签正在使用前一个对象。它有自己的指向前一个对象的指针。

      考虑这些事实以了解正在发生的事情:

      1. User currentUser = new User("Example Name");

        当你将一个对象赋给一个变量时,实际上这个变量指向了这个对象。

      1. lblName.DataBindings.Add("Text", currentUser, "Name");
        您对对象执行了数据绑定。控件将绑定到对象而不是变量。
      1. currentUser.Name = "Blahblah";

        您更改了Name 属性的值,并且由于您实现了INotifyPropertyChanged,控件将收到更改通知并刷新其Text。

      但主要语句没有按您的预期工作:

      1. currentUser = new User("New Name");

        在这里,您使currentUser 变量指向另一个对象。它与它指向的前一个对象没有任何关系。它只是指向另一个对象。

        您添加到标签的Binding 仍然使用之前的对象。

        所以没有任何通知是正常的,因为标签正在使用的对象没有改变。

      BindingSource 是如何解决问题的?

      当您将新对象分配给DataSource 时,BindingSource 引发ListChanged 事件,它使BindingObject 从DataSource 获取新值并刷新Text 属性。你可以看看这个帖子:How to make a binding source aware of changes in its data source?

      【讨论】:

      • 很好的解释!
      • The variable is just like a pointer to the object. So replacing the variable doesn't have any impact on the object which your label is using as data source. side 注意:这不要与具有不同绑定模型的WPF混淆( mvvm 面向):在这种情况下,当您分配new 值/指针时,绑定知道它已更改...
      • @MachineLearning 如果您创建一个模型Class1 包含Name 属性,然后将TextBox 绑定到Name 属性,然后定义var value = new Class1() { Name = "111" }; 然后设置this.grid1.DataContext = value; 然后设置value = new Class1() { Name = "222" };。什么都不会发生,您在TextBox 中看到的值将是相同的“111”。因为我上面描述的同样的事情。你们是男人吗?
      • 好的,(是的,我的意思是不同的,但是)你的比较是有道理的。完美,谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-21
      • 2018-05-03
      • 2016-09-07
      • 1970-01-01
      相关资源
      最近更新 更多