2

ComboBoxデフォルトの , TextBox(フォーカスを受け取るためだけに) と.を追加した空白のフォームがあります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

問題は、これが最初の選択のデータバインディングを壊すことです。コンボボックスは間違いなくフォーカスを失い、間違いなく new がSelectedValueあり、検証が確実に開始されましたが、データバインディングは新しい値をSomePropertyon に書き込みませんでしたsomeClass(セッターは決して開始せず、この例ではラベルは更新されません)。後続の選択では、セッターが起動します

必要に応じて、ComboBox1.SelectionChangeCommittedイベントから手動でデータバインディングを記述しますが、検証イベント中にもコードを処理する必要があるため、これは余分な作業のように感じます。

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

質問:

  • プログラムと手動でフォーカスを失うことは同じことをするべきではありませんか?
  • これが後続の選択では機能するのに、最初の選択では機能しないのはなぜですか?
  • これは実際には WinForms のバグですか、それとも何かひどく間違ったことをしたのでしょうか?

アップデート:

これまでの回答に感謝します。回避策よりも説明を探していたと思います。コントロールが検証されても、検証時に更新されるバインドされたプロパティが更新されないのはなぜでしょうか。さらに、なぜそれが初めてではなく、将来のすべてのイベントで機能するのでしょうか?

4

2 に答える 2

2

私はこれを別の方法で設定します。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上記では、コンボボックスが変更されたときにラベルが更新されるように、Label にバインドしていることに注意してください。

最後のビットはDataSourceUpdateMode、コンボボックスの を OnPropertyChanged に設定することです。これにより、そのイベント ハンドラーを取り除くことができます。

さらに良いことに、INotifyPropertyChangedをデータ バインドしていて、SomeClass への変更が UI に通知されるようにする必要があるため、 INotifyPropertyChangedSomeClassから継承する必要があります。

于 2013-07-09T20:00:56.830 に答える
1

質問 1 と 2 には正直に答えることができませんが、質問 3 に答えるためにこれを提供できます。

次の行を に追加しますFormLoad

ComboBox1.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged

これを Visual Studio 2010 でテストしたところ、ラベルから新しい値が選択されると、ラベルが適切に更新されますcombobox

于 2013-07-09T19:56:18.980 に答える