Combobox DataBinding Bug - Won't write value if programmatically losing focus

守給你的承諾、 提交于 2021-02-10 12:03:46

问题


I have a blank form, to which I've added a default ComboBox, TextBox (just for receiving focus), and Label. The combobox has a databinding set up to a private property on the form.

Setup:

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

Where someClass is a private variable of type SomeClass below:

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

Expected Behavior:

The default Binding.DataSourceUpdateMode is that changes will be propagated OnValidation.

If I select a value from the ComboBox and then click off it onto the TextBox, then the DataBinding will write the new value to the specified property and the Label on my main form will be updated.

Possible Bug:

The problem comes in because we have a business rule that requires us to perform validation immediately when a selection is made. In order for validation to fire, the ComboBox has to lose focus, so by adding the following code to the SelectionChangeCommitted event, we can programmatically force validation

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

The problem is that this breaks the databinding for the very first selection. The combobox has definitely lost focus, it definitely has a new SelectedValue and validation has definitely fired, but the databinding did not write the new value to SomeProperty on someClass (The setter never fires and the label, in this example, doesn't update). In subsequent selections, the setter will fire

If necessary, from the ComboBox1.SelectionChangeCommitted event, I'll manually write the databinding, but feel like this is extra work since I need to process code during the Validation Event as well.

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

Questions:

  • Shouldn't programmatically and manually losing focus do the same thing?
  • Why does this work on subsequent selections, but not on the first one?
  • Is this in fact some bug in WinForms, or have i done something horribly wrong?

Update:

Thanks for the answers so far. I guess I was looking more for an explanation than a workaround. Why would it be the case that a bound property that updates on validation doesn't update even when the control has validated. Further, why would it not happen the first time, but work for all future events?


回答1:


I would set this up differently. You really shouldn't be changing your UI from your SomeClass object. It should just store data:

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

Then, change your FormLoad and fix your data bindings so that everything is data bound:

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

Notice that above we bind someClass to your Label so that when the combobox is changed, the label will be updated.

The final bit is to set the DataSourceUpdateMode on your combobox to OnPropertyChanged which will allow you to get rid of that event handler.

Better still, you should have SomeClass inherit from INotifyPropertyChanged because you are data binding it and you want to make sure that changes to SomeClass will have it notify the UI.




回答2:


I can't honestly answer questions 1 and 2, but I can give you this to answer question 3. You didn't do anything terribly wrong, just didn't include a helpful line of code.

Add the following line to FormLoad:

ComboBox1.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged

I tested this out in Visual Studio 2010 and the label updates properly when a new value is selected from the combobox.



来源:https://stackoverflow.com/questions/17556487/combobox-databinding-bug-wont-write-value-if-programmatically-losing-focus

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!