У меня была та же проблема: элемент управления редактора работал, но значения не сохранялись. Основываясь на ответе Марка и некоторых дальнейших исследованиях, я его запустил.
Хотя мне нужна была эта функция для редактирования моих собственных элементов управления в DesignTime, я протестировал ее с помощью демонстрационного проекта с элементом управления PropertyGrid после прочтения следующей цитаты из Microsoft :
При разработке пользовательского UITypeEditor рекомендуется
установите номер сборки, чтобы увеличивать с каждой сборкой. Это мешает
старые кэшированные версии вашего UITypeEditor, созданные в
среда проектирования.
Я думаю, что это была проблема, которая вызывала проблемы при попытке реализовать решение Марка. Тестирование в отдельном проекте также полезно, потому что вы можете использовать пошаговую отладку, чтобы увидеть, что происходит в элементе управления, редакторе и конвертере.
Основные шаги:
- Создайте тип (здесь: MyFlags ) и свойство (здесь: MyProperty ), добавив некоторые дополнительные атрибуты к
последний.
- Реализация элемента управления (здесь: EnumEditorControl ), который будет использоваться для редактирования.
- Реализация класса
UITypeEditor
(здесь: EnumEditor ); это связано со свойством с помощью атрибута Editor
. Он также создает и управляет экземпляром нашего EnumEditorControl .
- Реализация класса
TypeConverter
(здесь: EnumConverter ); это также связано со свойством с помощью атрибута (TypeConverter
) и обрабатывает преобразование значения в строку для отображения в сетке свойств.
А теперь пошаговое руководство с соответствующими фрагментами кода:
Определите Enum
, используя атрибут Flags
.
<Flags>
Public Enum MyFlags
Flag1 = 2 ^ 0
Flag2 = 2 ^ 1
Flag3 = 2 ^ 2
End Enum
Определите свойство для пользовательского элемента управления.
Public Property MyProperty() As MyFlags
...
End Property
У этого свойства позже будут добавлены атрибуты, как только мы создадим другие необходимые нам компоненты (см. # 6).
Создайте нужный элемент управления, который будет использоваться для редактирования
свойство.
Imports System.Windows.Forms.Design
Public Class EnumEditorControl(Of T As Structure)
Public Sub New(value As Long, editorService As IWindowsFormsEditorService)
'This call is required by the Windows.Forms Form Designer.
InitializeComponent()
_value = value
_editorService = editorService
For Each item As Long In [Enum].GetValues(GetType(T))
Me.CheckedListBox1.Items.Add([Enum].GetName(GetType(T), item), (_value And item) = item)
Next
End Sub
Private _value As Long
Public Property Value As Long
Get
Return _value
End Get
Set(value As Long)
_value = value
End Set
End Property
Private _editorService As IWindowsFormsEditorService
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim v As Long = 0
For Each item As String In Me.CheckedListBox1.CheckedItems
v = (v Or [Enum].Parse(GetType(T), item))
Next
_value = v
Me._editorService.CloseDropDown()
End Sub
End Class
Выше приведен код класса без designer.vb частей. Важными частями являются: конструктор с параметрами value
и editorService
, заполнение элемента управления текущими выбранными значениями (в конструкторе) и реализация «действия коммита», когда свойство элемента управления Value
обновляется (в зависимости от на выбор сделан) и наконец звонит Me._editorService.CloseDropDown()
.
Определить универсальный UITypeEditor.
Imports System.ComponentModel
Imports System.Drawing.Design
Imports System.Windows.Forms.Design
Public Class EnumEditor(Of T As Structure)
Inherits UITypeEditor
Public Overrides Function GetEditStyle(context As ITypeDescriptorContext) As UITypeEditorEditStyle
Return UITypeEditorEditStyle.DropDown
End Function
Public Overrides ReadOnly Property IsDropDownResizable() As Boolean
Get
Return True
End Get
End Property
Public Overrides Function EditValue(context As ITypeDescriptorContext, provider As IServiceProvider, value As Object) As Object
Dim svc As IWindowsFormsEditorService = DirectCast(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)
Dim items As Long = CLng(value)
If svc IsNot Nothing Then
Dim c As New EnumEditorControl(Of T)(value, svc)
svc.DropDownControl(c)
value = c.Value
End If
Return CType(value, T)
End Function
End Class
Основной частью здесь является переопределение EditValue
, когда экземпляр нашего элемента управления редактора (см. # 3) создается и отображается с использованием svc.DropDownControl(c)
. И, наконец, получение выбранного значения из свойства нашего элемента управления и его возврат.
Определить универсальный TypeConverter , используемый для преобразования фактического значения в строковое представление, которое будет использоваться в проводнике свойств.
Импортирует System.ComponentModel
Импортирует System.Drawing.Design
Импортирует System.Text
Импортирует System.Windows.Forms.Design
Class EnumConverter(Of T As Structure)
Inherits TypeConverter
Public Overrides Function CanConvertTo(context As ITypeDescriptorContext, destinationType As Type) As Boolean
Return destinationType = GetType(String) OrElse MyBase.CanConvertTo(context, destinationType)
End Function
Public Overrides Function ConvertTo(context As ITypeDescriptorContext, culture As System.Globalization.CultureInfo, value As Object, destinationType As Type) As Object
If destinationType = GetType(String) Then
Dim items As Integer = CLng(value)
If items = 0 Then
Return ""
End If
Dim values As New List(Of String)
For Each item As Integer In [Enum].GetValues(GetType(T))
If (items And item) = item Then
values.Add([Enum].GetName(GetType(T), item))
End If
Next
Return String.Join(", ", values)
End If
Return MyBase.ConvertTo(context, culture, value, destinationType)
End Function
End Class
Свяжите все это, добавив следующие атрибуты к определенному свойству (см. # 2).
<Browsable(True),
DefaultValue(MyFlags.Flag1),
Editor(GetType(EnumEditor(Of MyFlags)),
GetType(System.Drawing.Design.UITypeEditor)),
TypeConverter(GetType(EnumConverter(Of MyFlags)))
>
Public Property MyProperty() As MyFlags
...
End Property
Примечание. Ссылаясь на упомянутое в вопросе «нулевое значение»: это решение не учитывает это, но его можно легко изменить для этого.