首页 > 解决方案 > 如何为数据绑定自定义组合框获取第二个 ValueMember

问题描述

我有一个简单的自定义组合框,它只添加了一个属性“ValueMember2”。

我已将组合框数据源添加到数据集

我可以像设置普通属性“ValueMember”一样在代码中设置属性

cboRadioType.ValueMember = "ID"
cboRadioType.ValueMember2 = "FREQMIN"
cboRadioType.DisplayMember = "MODEL"

正常的 ValueMember 属性将返回来自数据源的 ID 新的 ValueMember2 属性只返回字符串“FREQMIN”

我的自定义组合框代码如下:

Imports System.ComponentModel
Public Class NewCBO
Inherits ComboBox
Dim vm2 As String
<Description("Gets/Sets the ValueMember2 of Control")>
Property ValueMember2() As String
    Get
        ValueMember2 = vm2
    End Get
Set(ByVal Value As String)
    vm2 = Value
End Set
End Property
End Class

我需要更改我的自定义属性以使其从连接的数据源返回值?所有搜索都出现了如何“显示ValueMember”

标签: vb.net

解决方案


这是一个自定义ComboBox类,其中包括一个相当严格的实现,ValueMember2SelectedValue2基于现有的ValueMemberand实现SelectedValue

Imports System.ComponentModel

Public Class ComboBoxEx
    Inherits ComboBox

    Private _valueMember2 As BindingMemberInfo

    Public Property ValueMember2 As String
        Get
            Return _valueMember2.BindingMember
        End Get
        Set(value As String)
            If value Is Nothing Then
                value = String.Empty
            End If

            Dim bindingMemberInfo As New BindingMemberInfo(value)

            If bindingMemberInfo.Equals(_valueMember2) Then
                Return
            End If

            'This part is implemented in ValueMember but cannot be here because SetDataConnection is Private.
            'It may be possible to provide our own implement of SetDataConnection but that is not done here.
            'If DisplayMember.Length = 0 Then
            '    SetDataConnection(DataSource, bindingMemberInfo, False)
            'End If

            'This part is implemented in ValueMember but cannot be here because BindingMemberInfoInDataManager is Private.
            'It may be possible to provide our own implement of BindingMemberInfoInDataManager but that is not done here.
            'If DataManager IsNot Nothing AndAlso
            '   value <> String.Empty AndAlso
            '   Not BindingMemberInfoInDataManager(bindingMemberInfo) Then
            '    Throw New ArgumentException("...", NameOf(value))
            'End If

            _valueMember2 = bindingMemberInfo

            'A rigorous implementation should also include implementation of corresponding events.
            'OnValueMember2Changed(EventArgs.Empty)
            'OnSelectedValue2Changed(EventArgs.Empty)
        End Set
    End Property

    Public Property SelectedValue2 As Object
        Get
            Return If(SelectedIndex <> -1 AndAlso DataManager IsNot Nothing,
                      FilterItemOnProperty(DataManager.List(SelectedIndex), _valueMember2.BindingField),
                      Nothing)
        End Get
        Set(value As Object)
            If DataManager Is Nothing Then
                Return
            End If

            Dim bindingField = _valueMember2.BindingField

            If String.IsNullOrEmpty(bindingField) Then
                Throw New InvalidOperationException("...")
            End If

            'This part is implemented in ValueMember but cannot be here because DataManager.Find is Private.
            'SelectedIndex = DataManager.Find(DataManager.GetItemProperties().Find(bindingField, True), value, True)

            'The following replaces the call to DataManager.Find above.

            If value Is Nothing Then
                Throw New ArgumentNullException(NameOf(value))
            End If

            Dim newSelectedIndex = -1
            Dim [property] = DataManager.GetItemProperties().Find(bindingField, True)

            If [property] IsNot Nothing Then
                Dim list=DataManager.List
                Dim bindingList = TryCast(list, IBindingList)

                If bindingList?.SupportsSearching Then
                    newSelectedIndex = bindingList.Find([property], value)
                Else
                    For i = 0 To list.Count - 1
                        Dim obj = list(i)

                        If value.Equals(obj) Then
                            newSelectedIndex = i

                            Exit For
                        End If
                    Next
                End If
            End If

            SelectedIndex = newSelectedIndex
        End Set
    End Property

End Class

里面有一些你应该阅读的笔记。另请注意,缺少ValueMember设计时支持。ValueMember2使用同一个编辑器可能并不难,但我没有研究过。还值得注意的是ValueMemberandSelectedValue被实现ListControl,因此也被继承ListBox。您必须在自定义中单独实现此代码ListBox

我使用以下代码测试了该控件:

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim table As New DataTable

        With table.Columns
            .Add("Id", GetType(Integer))
            .Add("Name", GetType(String))
            .Add("DateOfBirth", GetType(Date))
        End With

        With table.Rows
            .Add(1, "Peter", #1/1/2001#)
            .Add(2, "Paul", #2/2/2002#)
            .Add(3, "Mary", #3/3/2003#)
        End With

        BindingSource1.DataSource = table

        With ComboBoxEx1
            .DisplayMember = "Name"
            .ValueMember = "Id"
            .ValueMember2 = "DateOfBirth"
            .DataSource = BindingSource1
        End With
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        MessageBox.Show($"ID: {ComboBoxEx1.SelectedValue}; Date of Birth: {ComboBoxEx1.SelectedValue2}", ComboBoxEx1.Text)
    End Sub

End Class

它完全按预期工作。相同的代码也应该适用于其他数据源,例如 a List(Of T),尽管我没有做任何额外的测试。


推荐阅读