我正在.net上的winform中工作,该人使用System.Reflection根据模型类自动生成控件,如下所示:
Imports System.Reflection
Public Class DynamicForm(Of Model As {IModelBase, Class, New})
Protected Sub InitializeComponent()
'A lot of not relevant code here...
For Each prop As PropertyInfo In GetType(Model).GetProperties
If Not HasControl(prop) Then Continue For
Dim control = CreateControl(prop)
Dim label = CreateLabel(prop)
SetLocation(label, control)
Me.Controls.Add(control)
Me.Controls.Add(label)
ResizeWindow(control.Height)
Next
End Sub
End Class
当然,模型可以具有很多我不希望用户直接编辑的属性,因此我采用了使用属性来标记要显示的属性的解决方案:
Public Class HasControl
Inherits Attribute
Public Property Label As String
Public Sub New(label As String)
Me.Label = label
End Sub
End Class
然后我的模型如下:
Public Class Clients
Implements IModelBase
<HasControl("First name:")>
Public Property FirstName As String
Public Property CreatedTime As Date
End Class
现在,我使用IModelBase接口只是为了确保在此窗口中不能使用任何类,但最近我开始将其用于其他用途。我的许多模型都类似于客户,工人,卖方,用户等。这些模型具有许多相似的属性,因此我使用以下属性创建了一个界面:
Public Interface IHumanData
Inherits IModelBase
<HasControl("First name:")>
Public Property FirstName As String
<HasControl("Last name:")>
Public Property LastName As String
End Interface
Public Class Seller
Implements IHumanData
Public Property FirstName As String Implements IHumanData.FirstName
Public Property LastName As String Implements IHumanData.LastName
End Class
此问题是“ HasControl”属性未分配给我的卖方属性。我知道如果我使用继承而不是接口实现可以正常工作,但是当我要创建类似这样的东西时,继承有一个局限性:
Public Class Worker
Implements IHumanData, IDateStorageData, ILocationData, ISortOfRandomData
' A bunch of properties auto generated by VisualStudio
End Class
那么,实际上有一种通过接口实现传递Attribute的简单方法吗?
答案 0 :(得分:1)
您应该在interface
定义中查询实现HasControl
attribute
的属性。
为此,您检索由表单中使用的对象实例实现的interfaces
。
构建表单的例程如下所示。
Sub buildForm(model As IModelBase)
Dim interfaceTypes As Type() = model.GetType().FindInterfaces(New TypeFilter(Function(t, c) True), Nothing)
For Each interfaceType As Type In interfaceTypes
Dim properties As PropertyInfo() = interfaceType.GetProperties()
For Each prop As PropertyInfo In properties
Dim attributes As IEnumerable(Of HasControlAttribute) = prop.GetCustomAttributes(Of HasControlAttribute)()
For Each attribute As HasControlAttribute In attributes
Console.Write(attribute.Name)
Console.Write(": ")
Console.WriteLine(CStr(prop.GetValue(model, Nothing)))
' Build label and control here ...
Next
Next
Next
End Sub
您还可以从通用类型参数(以interfaces
的形式)中检索这些Model
。
Dim interfaceTypes As Type() = GetType(Model).FindInterfaces(New TypeFilter(Function(t, c) True), Nothing)
通过将表单中正在使用的对象实例传递给它来调用它。 Worker
实例。
Dim worker As Worker = New Worker()
worker.FirstName = "John"
worker.LastName = "Doe"
worker.City = "Brussels"
worker.Age = 40
buildForm(worker)
只考虑标记属性。
请注意,属性Age
(如在Worker
上定义的示例未出现。
First name: John
Last name: Doe
City: Brussels
IModelBase
Public Interface IModelBase
' ...
End Interface
具有Control属性
Public Class HasControlAttribute
Inherits Attribute
Public Sub New(ByVal name As String)
Me.Name = name
End Sub
Public Property Name As String
End Class
IHumanData
Public Interface IHumanData
Inherits IModelBase
<HasControl("First name")>
Property FirstName As String
<HasControl("Last name")>
Property LastName As String
'...
End Interface
ILocationData
Public Interface ILocationData
<HasControl("City")>
Property City As String
' ...
End Interface
ISortOfRandomData
Public Interface ISortOfRandomData
'...
End Interface
工人
Public Class Worker
Implements IHumanData, ILocationData
Public Property FirstName As String Implements IHumanData.FirstName
Public Property LastName As String Implements IHumanData.LastName
Public Property City As String Implements ILocationData.City
Public Property Age As Integer
' ...
End Class
更新
跟进您的评论。
如果您要包含Worker
类本身定义的属性(未在任何已实现的接口中定义),如下所示,
那么interfaceTypes
数组需要包含对象实例本身的Type
。
Dim interfaceTypes As IList(Of Type) = model.GetType().FindInterfaces(New TypeFilter(Function(t, c) True), Nothing).ToList()
interfaceTypes.Add(model.GetType)
工人,其属性Age
标记为HasControl
Public Class Worker
Implements IHumanData, ILocationData
Public Property FirstName As String Implements IHumanData.FirstName
Public Property LastName As String Implements IHumanData.LastName
Public Property City As String Implements ILocationData.City
<HasControl("Age")>
Public Property Age As Integer
' ...
End Class