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!