按 属性 搜索绑定列表
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项上真的只有一个属性:Key
。 Value
是一种类型,这意味着您可能需要 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,而其他属性可能需要一个 string
或 DateTime
变量。
如前所述,如果找不到您想要的,FirstOrDefault
将一事无成。在第二个示例中搜索 Client
对象将要求 c
与列表中的对象完全相同。不同的客户端对象即使具有相同的 属性 值 也不会匹配 。如果需要,您可以实现自己的比较器。
由于 Value
可以是 Nothing,任何涉及它的查询都应该考虑到这一点:
NVC = Clients.
FirstOrDefault(Function(q) q.Value IsNot Nothing AndAlso
q.Value.Foo = "Q")
您项目 class 中的一些代码也应该考虑到这一点,或者更改它以便在没有 Client
对象的情况下无法创建项目。
我的程序中有一个绑定列表,我想向其中添加一些元素。这些元素是 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项上真的只有一个属性:Key
。 Value
是一种类型,这意味着您可能需要 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,而其他属性可能需要一个 string
或 DateTime
变量。
如前所述,如果找不到您想要的,FirstOrDefault
将一事无成。在第二个示例中搜索 Client
对象将要求 c
与列表中的对象完全相同。不同的客户端对象即使具有相同的 属性 值 也不会匹配 。如果需要,您可以实现自己的比较器。
由于 Value
可以是 Nothing,任何涉及它的查询都应该考虑到这一点:
NVC = Clients.
FirstOrDefault(Function(q) q.Value IsNot Nothing AndAlso
q.Value.Foo = "Q")
您项目 class 中的一些代码也应该考虑到这一点,或者更改它以便在没有 Client
对象的情况下无法创建项目。