Как использовать сетку свойств в форме для редактирования любого типа - PullRequest
3 голосов
/ 22 июля 2009

У меня есть приложение, в котором я хотел бы иметь возможность редактировать любой тип (шрифт, цвет, точка и т. Д.) Во время выполнения и использовать любой из стандартных редакторов типов .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)

Если я передаю объект в сетку свойств, он работает, но не работает, если я передаю экземпляр оболочки.

Я решил проблему с помощью отражения. Emit для создания не универсальной оболочки необходимого типа на лету, но я подозреваю, что это слишком.

Есть идеи?

ETA:

У меня была проблема с тем, что делать, если я использовал Grid для редактирования свойства, скажем шрифта, которое еще не было определено.

Если я определю:

Dim f as Font = Nothing

и передайте это оболочке, сетка свойств будет отображаться, как и ожидалось, с (нет) и кнопкой с ..., чтобы выбрать шрифт.

Моя проблема заключалась в том, как сделать эквивалент 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

Проблема решена!

1 Ответ

3 голосов
/ 22 июля 2009

Я думаю, что это должно работать. Я протестировал его на C # и использовал конвертер для получения кода на VB.net

Это код в C #

Type generic = typeof(Wrapper<>);
Type specific = generic.MakeGenericType(o.GetType());
ConstructorInfo ci = specific.GetConstructor(new Type[] { o.GetType() });
object o1 = ci.Invoke(new object[] { o });
propertyGrid1.SelectedObject = o1;

VB.NET

Dim generic As Type =  Type.GetType(Wrapper<>) 
Dim specific As Type =  generic.MakeGenericType(o.GetType()) 
Dim ci As ConstructorInfo =  specific.GetConstructor(New Type() {o.GetType() })
Dim o1 As Object =  ci.Invoke(New Object(){  o })
propertyGrid1.SelectedObject = o1
...