【问题标题】:Databinding to TextBox - setting Text property in code doesn't update model数据绑定到 TextBox - 在代码中设置 Text 属性不会更新模型
【发布时间】: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 上的布尔属性。

【问题讨论】:

    标签: c# .net winforms data-binding


    【解决方案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 可以为您的模型类启用双向数据绑定。

    【讨论】:

      猜你喜欢
      • 2015-09-25
      • 1970-01-01
      • 2015-11-27
      • 1970-01-01
      • 2011-04-05
      • 2021-12-18
      • 2010-11-10
      • 2011-01-14
      • 1970-01-01
      相关资源
      最近更新 更多