按 属性 搜索绑定列表

Search BindingList by property

我的程序中有一个绑定列表,我想向其中添加一些元素。这些元素是 class NameValue_Client 的一些实例,其中包含三个属性。我想使用我想要的任何 属性 搜索列表。

这是class:

Public Class NameValue_Client
    Implements INotifyPropertyChanged

    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    Private _assigned_db_name As String, _assigned_tcp_name As String
    Private _val_obj As Client
    Private _key_obj As Integer


    Public WriteOnly Property DB_Name As String
        Set(ByVal value As String)
            _assigned_db_name = value
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("DB_Name"))
        End Set
    End Property

    Public Property Value As Client
        Get
            Return _val_obj
        End Get
        Set(ByVal value As Client)
            _val_obj = value
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Value"))
        End Set
    End Property

    Public Property Key As Integer
        Get
            Return _key_obj
        End Get
        Set(ByVal value As Integer)
            _key_obj = value
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Key"))
        End Set
    End Property

    Public ReadOnly Property Name_Identifier As String
        Get
            Return String.Format("{0} : {1}", _assigned_db_name, _assigned_tcp_name)
        End Get
    End Property



    Sub New(ByVal Key As Integer, ByVal DB_Name As String)
        _assigned_db_name = DB_Name
        _key_obj = Key
    End Sub

    Private Sub changed(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Handles Me.PropertyChanged
        If e.PropertyName = "Value" Then
            If _val_obj IsNot Nothing Then
                _assigned_tcp_name = _val_obj.Details.Computer_Name
            End If
        End If
    End Sub

    Public Overrides Function ToString() As String
        If _val_obj IsNot Nothing Then
            Return String.Format("Db_Name:{0} Tcp_Name:{1} {2}", _assigned_db_name, _assigned_tcp_name, _val_obj.ToString)
        Else
            Return String.Format("Db_Name:{0} Tcp_Name:{1} Nothing", _assigned_db_name, _assigned_tcp_name)
        End If
    End Function
End Class

我在 MSDN 上找到了这个,它看起来是解决方案,但它只搜索一个 属性,我不想放一个 select 案例。它必须是更好的方法。

这是我找到的代码:

Public Class MyFontList
    Inherits BindingList(Of Font)

    Protected Overrides ReadOnly Property SupportsSearchingCore() As Boolean
        Get
            Return True
        End Get
    End Property

    Protected Overrides Function FindCore(ByVal prop As PropertyDescriptor, _
        ByVal key As Object) As Integer
        ' Ignore the prop value and search by family name.<--That's why
        Dim i As Integer
        While i < Count
            If Items(i).FontFamily.Name.ToLower() = CStr(key).ToLower() Then
                Return i
            End If
            i += 1
        End While

        Return -1
    End Function
End Class

而且我不知道如何实现这个 'child' class(从未使用过这种类型)。


这是我的代码(到目前为止):

Public Class NameValue_Client
    Implements INotifyPropertyChanged

    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    Private _assigned_db_name As String, _assigned_tcp_name As String
    Private _val_obj As Client
    Private _key_obj As Integer


    Public WriteOnly Property DB_Name As String
        Set(ByVal value As String)
            _assigned_db_name = value
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("DB_Name"))
        End Set
    End Property

    Public Property Value As Client
        Get
            Return _val_obj
        End Get
        Set(ByVal value As Client)
            _val_obj = value
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Value"))
        End Set
    End Property

    Public Property Key As Integer
        Get
            Return _key_obj
        End Get
        Set(ByVal value As Integer)
            _key_obj = value
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Key"))
        End Set
    End Property

    Public ReadOnly Property Name_Identifier As String
        Get
            Return String.Format("{0} : {1}", _assigned_db_name, _assigned_tcp_name)
        End Get
    End Property



    Sub New(ByVal Key As Integer, ByVal DB_Name As String)
        _assigned_db_name = DB_Name
        _key_obj = Key
    End Sub

    Private Sub changed(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Handles Me.PropertyChanged
        If e.PropertyName = "Value" Then
            If _val_obj IsNot Nothing Then
                _assigned_tcp_name = _val_obj.Details.Computer_Name
            End If
        End If
    End Sub

    Public Overrides Function ToString() As String
        If _val_obj IsNot Nothing Then
            Return String.Format("Db_Name:{0} Tcp_Name:{1} {2}", _assigned_db_name, _assigned_tcp_name, _val_obj.ToString)
        Else
            Return String.Format("Db_Name:{0} Tcp_Name:{1} Nothing", _assigned_db_name, _assigned_tcp_name)
        End If
    End Function
End Class

Public Class Interface_NameValue
    Inherits BindingList(Of NameValue_Client)

    Protected Overrides ReadOnly Property SupportsSearchingCore() As Boolean
        Get
            Return True
        End Get
    End Property

    Protected Overrides Function FindCore(ByVal prop As PropertyDescriptor, _
        ByVal key As Object) As Integer

        ' Ignore the prop value and search by family name.
        Dim i As Integer

        While i < Count
            ''Old-fashion way
            Select Case prop.Name
                Case "Value"
                Case "Key"
                Case "Name_Identifier"
            End Select
            i += 1
        End While

        Return -1
    End Function
End Class

现在我应该用这个新 class 做什么?我该如何实施?

I want to search through the list using any property I want...and I don't want to put a select case .

来自 MSDN 的 MyFontList class 展示了实现集合的部分操作 class - 注意 Inherits BindingList(Of Font) - 而不是修改 item class (NameValue_Client)。您的代码会使用 class 代替 BindingList(of NameValue_Client) 集合变量。

有一个更简单的方法。

首先,尽管您的项目 class 没有理由订阅它自己的 PropertyChanged 事件。只需将 Value setter 更改为:

Set(ByVal value As Client)
    _val_obj = value
    If _val_obj IsNot Nothing Then
        _assigned_tcp_name = _val_obj.ComputerName
    End If
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Value"))
End Set

更新 _assigned_tcp_name 引发事件之前,新值将对任何订阅事件并可能使用 Name_Identifier 的对象可见。但是你应该考虑摆脱 _assigned_tcp_name 因为它允许它成为 "stale":

的可能性
Public ReadOnly Property Name_Identifier As String
    Get
        Dim tcpname = If(Value IsNot Nothing, Value.ComputerName, "")
        Return String.Format("{0} : {1}", _assigned_db_name, tcpname)
    End Get
End Property

KeyValuePair 类型 class 似乎也很奇怪,其中 Value 基本上是可选的(显然是手动设置的)。它甚至根本不需要存在,因此可以有一个没有 Value.

Key

说到搜索,class项上真的只有一个属性:KeyValue 是一种类型,这意味着您可能需要 Client 上的任意数量的属性之一。 DB_Name是WriteOnly(?!),所以无法搜索到;我猜你可能会搜索 Name_Identifier 但那是一个化合物,'artificial' 属性.

我们只能在 Client 上看到 1 属性,所以我添加了一些用于说明目的:

Public Class Client
    Public Property ComputerName As String
    Public Property Foo As String
    Public Property Bar As Int32

    Public Sub New(n As String)
        ComputerName = n
    End Sub
End Class

您可以使用 linq 来查找您想要的任何内容:

Dim Clients As New BindingList(Of NameValue_Client)

Dim c = New Client("ziggy") With {.Bar = 9, .Foo = "9"}
Dim NVC = New NameValue_Client(1, "Alpha")
NVC.Value = c
Clients.Add(NVC)

c = New Client("zoey") With {.Bar = 7, .Foo = "Q"}
NVC = New NameValue_Client(2, "Beta")  With {.Value = c}
Clients.Add(NVC)

' find a key:
NVC = Clients.FirstOrDefault(Function(q) q.Key = 1)
' find a client object:
NVC = Clients.FirstOrDefault(Function(q) q.Value Is c)
' find a client.computername:
NVC = Clients.FirstOrDefault(Function(q) q.Value.ComputerName = "Mine")
' find a client.foo value
NVC = Clients.FirstOrDefault(Function(q) q.Value.Foo = "Q")

' return is Nothing if not found:
If NVC Is Nothing Then
    ' NOT FOUND!
Else
    ' found
    Console.WriteLine(NVC.Name_Identifier)
End If

您搜索的内容可以是一个变量,但是搜索 Key (int) 当然需要一个 int var,而其他属性可能需要一个 stringDateTime 变量。

如前所述,如果找不到您想要的,FirstOrDefault将一事无成。在第二个示例中搜索 Client 对象将要求 c 与列表中的对象完全相同。不同的客户端对象即使具有相同的 属性 值 也不会匹配 。如果需要,您可以实现自己的比较器。

由于 Value 可以是 Nothing,任何涉及它的查询都应该考虑到这一点:

NVC = Clients.
        FirstOrDefault(Function(q) q.Value IsNot Nothing AndAlso
                                 q.Value.Foo = "Q")

您项目 class 中的一些代码也应该考虑到这一点,或者更改它以便在没有 Client 对象的情况下无法创建项目。