数据绑定到 TextBox - 在代码中设置 Text 属性不会更新模型

Posted

技术标签:

【中文标题】数据绑定到 TextBox - 在代码中设置 Text 属性不会更新模型【英文标题】:Databinding to TextBox - setting Text property in code doesn't update model 【发布时间】:2021-04-02 04:30:29 【问题描述】:

我正在使用 WinForms/C# 处理一些数据收集表单。当表单加载时,我循环配置并为每个 TextBox 控件添加一个新的绑定;将每个 TextBox 控件的 Text 属性映射到我的 POCO 对象上的特定字符串属性。

public void BindTextBoxControls(dynamic entity, List<TextBoxConfig> textBoxConfig)

    foreach (var config in textBoxConfig)
        config.Control.DataBindings.Add(new Binding("Text", entity, config.PropertyName));

一切都按预期工作,新记录正确保存输入到相应 TextBox 控件中的新值,在重新打开之前使用表单输入的记录时,TextBox 填充了正确的值,并且更新了之前输入记录的 TextBoxes 中的值获取在基础 POCO 上设置的更新值。

但是,我开始在表单上添加一些业务规则,专门根据表单上的其他用户输入/活动来灰显/禁用和清除 TextBox 中先前输入的值 - 事情没有按预期工作。

在一个人为的例子中;一条规则,例如如果选中了 Checkbox_1,则不应评估 TextBox #5(清除任何先前输入的值并将其从输入中禁用)。在 CheckedChanged 的​​ Checkbox_1 事件处理程序中,我专门检查 Checkbox_1 是否被选中,如果是,则设置 TextBox_1.Text == null 和 TextBox_1.Enabled = false。这按预期工作,在表单上,​​我看到任何以前输入的值都从 TextBox_1 中清除,并且它已启用。

    private void chkCheckBox1_CheckedChanged(object sender, EventArgs e)
    
        if(!chkCheckBox1.Checked)
        
            txtBox5.Text = string.Empty;
        
    

但是,当我调试和中断保存并检查调用方法后底层控件绑定到的底层 POCO 属性时;尽管文本框没有值出现在表单上,​​但旧值仍保留在文本框绑定到的对象属性上。当我重新打开该记录的表单时,旧的清除值会重新填充到禁用的文本框中。但是,手动清除同一 TextBox 中的值或更新值并检查对象会在执行这些操作后显示更新的值。

似乎在代码中更改 TextBox 控件的 Text 值(例如 TextBox 的 Text 属性)可能会以某种方式“绕过”DataBinding?在事件处理程序方法中以编程方式将类似规则应用到“取消选中”文本框时,我实际上看到了相同/相似的行为 - CheckBox 控件也使用 DataBinding 来处理 POCO 上的布尔属性。

【问题讨论】:

【参考方案1】:

当你通过这个重载设置数据绑定时:Binding(String, Object, String),那么DataSourceUpdateMode的值将是OnValidation,这意味着当你使用代码或通过UI修改控件的属性值时,绑定将推送新的仅在控件发生Validating 事件后才向数据源赋值。

要解决此问题,请使用以下任一选项:

使用另一个重载并将DataSourceUpdateMode 设置为OnProperetyChanged OR,在设置TextBox.Text 的Value 后调用表单的ValidateChildren 方法。

示例 - 将 DataSourceUpdateMode 设置为 OnProperetyChanged

public class Person

    public string Name  get; set; 
    public string LegalCode  get; set; 
    public bool IsRealPerson  get; set; 

Person person;
private void Form1_Load(object sender, EventArgs e)

    person = new Person()  
        Name = "My Company", LegalCode = "1234567890", IsRealPerson = false ;

    NameTextBox.DataBindings.Add(nameof(TextBox.Text), person,
        nameof(Person.Name), true, DataSourceUpdateMode.OnPropertyChanged);
    LegalCodeTextBox.DataBindings.Add(nameof(TextBox.Text), person, 
        nameof(Person.LegalCode), true, DataSourceUpdateMode.OnPropertyChanged);
    IsRealPersonCheckBox.DataBindings.Add(nameof(CheckBox.Checked), person, 
        nameof(Person.IsRealPerson), true, DataSourceUpdateMode.OnPropertyChanged);

    IsRealPersonCheckBox.CheckedChanged += (obj, args) =>
    
        if (IsRealPersonCheckBox.Checked)
        
            LegalCodeTextBox.Text = null;
            LegalCodeTextBox.Enabled = false;
        
    ;

注意 - 您可以将逻辑放入模型中

另一个解决方案(这需要更多的努力和更多的代码更改)是在你的模型类中实现INotifyPropertyChanged。然后当 PropertyChanged 为您的布尔属性引发事件时,您可以检查它是否为假,然后您可以将字符串属性设置为 null。

在这种方法中,您不需要处理 UI 事件。同样在更新模型属性后,UI 也会更新;事实上,实现INotifyPropertyChanged 可以为您的模型类启用双向数据绑定。

【讨论】:

以上是关于数据绑定到 TextBox - 在代码中设置 Text 属性不会更新模型的主要内容,如果未能解决你的问题,请参考以下文章

WPF 在代码隐藏中设置 TextBox 属性

如果 ASP.Net 中的数据库值为空,则在 TextBox 中设置空字符串不起作用

winform中设置dataview.allowedit=false后,怎样使textbox不能修改数据

c#设置TextBox的FontSize

WPF:一旦我在代码中设置了一个属性,它就会永远忽略 XAML 绑定......我该如何防止这种情况发生?

Android 数据绑定,从函数调用中设置 xml 样式