【问题标题】:Combobox DataBinding Bug - Won't write value if programmatically losing focus组合框数据绑定错误 - 如果以编程方式失去焦点,则不会写入值
【发布时间】:2013-07-09 19:23:44
【问题描述】:

我有一个空白表单,其中添加了默认的ComboBoxTextBox(仅用于接收焦点)和Label。组合框有一个数据绑定设置到表单上的私有属性。

设置:

Private Sub FormLoad(sender As System.Object, e As System.EventArgs) _
      Handles MyBase.Load
    Dim data = {New With {.Display = "", .Value = ""},
                New With {.Display = "A", .Value = "A"},
                New With {.Display = "B", .Value = "B"},
                New With {.Display = "C", .Value = "C"}}

    ComboBox1.DataSource = data
    ComboBox1.DisplayMember = "Display"
    ComboBox1.ValueMember = "Value"
    ComboBox1.DataBindings.Add("SelectedValue", someClass, "SomeProperty")
End Sub

其中 someClass 是下面SomeClass 类型的私有变量:

Public Class SomeClass

    Private _someProperty As String = ""

    Public Property SomeProperty() As String
        Get
            Return _someProperty
        End Get
        Set(ByVal value As String)
            _someProperty = value
            Form1.Label1.Text = String.Format("Some property = ""{0}""", value)
        End Set
    End Property

End Class

预期行为:

默认Binding.DataSourceUpdateMode 是更改将传播OnValidation

如果我从ComboBox 中选择一个值,然后在TextBox 上单击它,则DataBinding 会将新值写入指定的属性,并且我的主窗体上的标签将被更新。

可能的错误:

问题出现是因为我们有一个业务规则,要求我们在做出选择时立即执行验证。为了触发验证,ComboBox 必须失去焦点,因此通过将以下代码添加到 SelectionChangeCommitted 事件,我们可以以编程方式强制验证

Private Sub ComboChanged(sender As System.Object, e As EventArgs) _
        Handles ComboBox1.SelectionChangeCommitted
    TextBox1.Focus()
End Sub

问题在于这会破坏第一次选择的数据绑定。组合框肯定失去了焦点,它肯定有一个新的SelectedValue,并且验证肯定已经触发,但是数据绑定没有将新值写入someClass 上的SomeProperty(在这个例子中,setter 永远不会触发和标签,不更新)。在随后的选择中,setter 将触发

如有必要,我将从ComboBox1.SelectionChangeCommitted 事件中手动编写数据绑定,但感觉这是额外的工作,因为我还需要在验证事件期间处理代码。

ComboBox1.DataBindings.Item("SelectedValue").WriteValue()

问题:

  • 不应该以编程方式和手动失去焦点做同样的事情吗?
  • 为什么这对后续选择有效,但对第一个选择无效?
  • 这实际上是 WinForms 中的一些错误,还是我做错了什么?

更新:

感谢到目前为止的回答。我想我更多的是寻找解释而不是解决方法。为什么即使控件已验证,在验证时更新的绑定属性也不会更新。此外,为什么它不是第一次发生,而是适用于所有未来的事件?

【问题讨论】:

    标签: vb.net winforms


    【解决方案1】:

    我会以不同的方式进行设置。您真的不应该从 SomeClass 对象更改您的 UI。它应该只存储数据:

    Public Class SomeClass
    
        Private _someProperty As String = ""
    
        Public Property SomeProperty() As String
            Get
                Return _someProperty
            End Get
            Set(ByVal value As String)
                _someProperty = value
            End Set
        End Property
    
    End Class
    

    然后,更改您的 FormLoad 并修复您的数据绑定,以便所有内容都是数据绑定:

    Private Sub FormLoad(sender As System.Object, e As System.EventArgs) _
          Handles MyBase.Load
        Dim data = {New With {.Display = "", .Value = ""},
                    New With {.Display = "A", .Value = "A"},
                    New With {.Display = "B", .Value = "B"},
                    New With {.Display = "C", .Value = "C"}}
    
        Label1.DataBindings.Add("Text", someClass, "SomeProperty");
    
        ComboBox1.DataSource = data
        ComboBox1.DisplayMember = "Display"
        ComboBox1.ValueMember = "Value"
        ComboBox1.DataBindings.Add("SelectedValue", someClass, "SomeProperty", 
              false, DataSourceUpdateMode.OnPropertyChanged)
    End Sub
    

    请注意,上面我们将someClass 绑定到您的标签,这样当组合框更改时,标签也会更新。

    最后一点是将组合框上的 DataSourceUpdateMode 设置为 OnPropertyChanged,这将允许您摆脱该事件处理程序。

    更好的是,您应该让 SomeClass 继承自 INotifyPropertyChanged,因为您正在对其进行数据绑定,并且您希望确保对 SomeClass 的更改会通知 UI。

    【讨论】:

    • 谢谢,标签文本更新只是我懒得看这个示例代码,但不在实际代码库中。
    • 我遇到了一个问题,我们有一些在 Validated 事件期间触发的 IsDirty 逻辑。当我使用OnPropertyChangedDataSourceUpdateMode 时,肯定会写入新的属性值(这很好),但直到执行验证后才会更新,因此即使 IsDirty 验证检查为空价值已经(最终)会改变。
    • @KyleMit,这是让您的下属数据对象实现INotifyPropertyChanged 的另一个原因。与其捕获 Validated 事件来处理 IsDirty,不如处理数据对象的 PropertyChanged 事件。
    【解决方案2】:

    我不能诚实地回答问题 1 和 2,但我可以给你这个来回答问题 3。你没有做任何严重的错误,只是没有包含有用的代码行。

    将以下行添加到FormLoad

    ComboBox1.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged
    

    我在 Visual Studio 2010 中对此进行了测试,当从 combobox 中选择新值时,标签会正确更新。

    【讨论】:

      猜你喜欢
      • 2010-11-16
      • 1970-01-01
      • 2013-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多