如何使用表单中的属性网格来编辑任何类型
我有一个应用程序,我希望能够在运行时编辑任何类型(字体、颜色、点等)并使用任何 .Net 默认类型编辑器。 (例如,字体/颜色选择器)。
我决定使用属性网格控件,而不是重新发明轮子。
如果我将一个对象(例如字体)传递到网格,它会单独列出所有字段,并且没有打开字体选择器的选项。
因此,我创建了这个通用包装器类:
Private Class Wrapper(Of T)
Private _Value As T
Public Property Value() As T
Get
Return Me._Value
End Get
Set(ByVal value As T)
Me._Value = value
End Set
End Property
Public Sub New(ByVal Value As T)
Me._Value = Value
End Sub
End Class
我传递了包装器的实例,而不是将字体对象传递到网格。 然后属性网格的行为就像我想要的那样。
这是可行的,但问题是,对象可以是任何类型,我无法编写类似的代码 -
Dim MyWrapper = New Wrapper(of T)(myObject).
基本上,我拥有的信息是类型的程序集限定名称和对象的字符串表示形式。 然后,我使用类型转换器来创建对象:
Dim ID As String = "System.Drawing.Font, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
Dim PropertyValue As String = "Arial, 12px, style=Bold, Strikeout"
Dim T As Type = System.Type.GetType(ID)
Dim tc As TypeConverter = TypeDescriptor.GetConverter(T)
Dim o As Object = tc.ConvertFromString(PropertyValue)
如果我将对象传递给属性网格,它可以工作,但如果我传递包装器的实例,它就不起作用。
我已经通过使用 Reflection.Emit 动态创建所需类型的非通用包装器解决了这个问题,但我怀疑这已经过头了。
有任何想法吗?
ETA:
如果我使用网格编辑尚未定义的属性(例如字体),我会遇到一个问题,该怎么办。
如果我定义:
Dim f as Font = Nothing
并将其传递给包装器,属性网格将按预期显示 (none) 和一个带有 ... 的按钮来选择字体。
我的问题是如何在运行时执行相当于 Dim myObject As 'Type' = Nothing 的操作。
我找不到办法做到这一点,但幸运的是,对于包装器和我的类型,这不是问题。 我将普拉迪普的代码(查看答案)更改为:
Dim genericType As Type = GetType(Wrapper(Of ))
Dim specificType As Type = genericType.MakeGenericType(T)
Dim ci As ConstructorInfo = specificType.GetConstructor(New Type() {T})
Dim wrappedObject As Object = ci.Invoke(New Object() {Nothing})
Me.PropertyGrid1.SelectedObject = wrappedObject
问题解决了!
I have an App where I'd like to be able to edit any type (font, colour, point etc.) at run time and use any of the .Net default type editors. (e.g., font/ colour picker).
Rather than re-invent the wheel, I decided to use the property grid control.
If I pass an object of, say font, to the grid, it lists all the fields separately, with no option to open the font picker.
Therefore, I created this generic wrapper class:
Private Class Wrapper(Of T)
Private _Value As T
Public Property Value() As T
Get
Return Me._Value
End Get
Set(ByVal value As T)
Me._Value = value
End Set
End Property
Public Sub New(ByVal Value As T)
Me._Value = Value
End Sub
End Class
Instead of passing a font object to the grid, I pass an instance of the wrapper. The property grid then behaves as I would like.
This works, but the problem is, the object could be of any type and I can't code something like -
Dim MyWrapper = New Wrapper(of T)(myObject).
Basically, the information I have is the type's assembly qualified name and a string representation of the object. I then use a type converter to create the object :
Dim ID As String = "System.Drawing.Font, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
Dim PropertyValue As String = "Arial, 12px, style=Bold, Strikeout"
Dim T As Type = System.Type.GetType(ID)
Dim tc As TypeConverter = TypeDescriptor.GetConverter(T)
Dim o As Object = tc.ConvertFromString(PropertyValue)
If I pass the object to the property grid, it works but it doesn't work if I pass an instance of the wrapper.
I've solved the problem by using reflection.Emit to create a non generic wrapper of the required type on the fly, but I suspect this is over kill.
Any ideas?
ETA:
I had a problem with what do to if I was using the Grid to edit a property, say a Font, that was not already defined.
If i define:
Dim f as Font = Nothing
, and pass that to the wrapper, the property grid displays as expected with (none) and a button with ... to select the font.
My problem was how to do the equivalent of Dim myObject As 'Type' = Nothing, at run-time.
I couldn't find a way to do this, but luckily with the wrapper and my type, it wasn't a problem.
I changed Pradeep's code (look at the answers) to :
Dim genericType As Type = GetType(Wrapper(Of ))
Dim specificType As Type = genericType.MakeGenericType(T)
Dim ci As ConstructorInfo = specificType.GetConstructor(New Type() {T})
Dim wrappedObject As Object = ci.Invoke(New Object() {Nothing})
Me.PropertyGrid1.SelectedObject = wrappedObject
Problem solved!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为这应该有效。 我已经在 C# 中对其进行了测试,并使用转换器在 VB.net 中获取代码
中的代码
这是 C# VB.NET
I think this should work. I've tested it in C# and used a converter to get code in VB.net
This is the code in C#
VB.NET