СЦЕНАРИЙ
Я подклассифицировал ListBox
и я добавил свойства цвета, когда мой элемент управления включен, отключен или в режиме ReadOnly:
ВОПРОС
В С# или VB.Net, что мне нужно сделать, чтобы упорядочить свойства в сетке свойств в расширяемые группы с помощью этой структуры?:
[+] State Enabled
[+] Selected Item
· BackColor
· ForeColor
[+] Unselected Item
· BackColor
· ForeColor
Это визуальный пример, взятый из пользовательского элемента управления Krypton
lib, который демонстрирует, что я хотел бы подражать:
ОБНОВИТЬ
Я думаю, что в этом url объясняется все необходимое о сетях свойств:
http://www.codeproject.com/Articles/2764/Using-PropertyGrid-Part-I
Но он сфокусирован на том, чтобы сделать это с формой, которая имеет событие Load, я все еще не могу понять, как реализовать этот пример в моем пользовательском элементе управления, потому что, если я создаю подкласс для настройки сетки свойств, как в этом примере, тогда я могу 't соответствует моему базовому классу управления.
Мой код имеет простую структуру:
Public Class ElektroListBox : Inherits ListBox
<Category("Appearance")>
<Description("The BackColor to paint the selected item when the control is enabled.")>
Public Property StateEnabledItemSelectedBackColor As Color
Get
Return Me.stateEnabledItemSelectedBackColor1
End Get
Set(ByVal value As Color)
Me.stateEnabledItemSelectedBackColor1 = value
Me.Invalidate(invalidateChildren:=False)
End Set
End Property
Private stateEnabledItemSelectedBackColor1 As Color = Color.Red
End Class
Первое, что вам нужно сделать, это структурировать ваши свойства в классы. Затем вам нужно создать настраиваемый конвертер типов для каждого класса, чтобы он стал сериализуемым. Однако есть более простой способ добиться этого; наследует класс Component. Вот простой пример.
Public Class UIListBox
Inherits ListBox
Public Sub New()
Me.m_stateDisabled = New ItemLayout(Me)
Me.m_stateEnabled = New ItemLayout(Me)
Me.m_stateReadOnly = New ItemLayout(Me)
End Sub
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
Public ReadOnly Property StateDisabled() As ItemLayout
Get
Return Me.m_stateDisabled
End Get
End Property
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
Public ReadOnly Property StateEnabled() As ItemLayout
Get
Return Me.m_stateEnabled
End Get
End Property
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
Public ReadOnly Property StateReadOnly() As ItemLayout
Get
Return Me.m_stateReadOnly
End Get
End Property
Friend Sub NotifyStateChanged(source As ItemLayoutColors, propertyName As String)
Me.Invalidate()
Debug.WriteLine("UIListBox: State changed.")
End Sub
Private m_stateDisabled As ItemLayout
Private m_stateEnabled As ItemLayout
Private m_stateReadOnly As ItemLayout
End Class
<ToolboxItem(False)>
Public Class ItemLayout
Inherits Component
Public Sub New(listBox As UIListBox)
Me.m_listBox = listBox
Me.m_background = New ItemLayoutColors(Me)
Me.m_foreground = New ItemLayoutColors(Me)
End Sub
Friend ReadOnly Property ListBox() As UIListBox
Get
Return Me.m_listBox
End Get
End Property
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
Public ReadOnly Property Background() As ItemLayoutColors
Get
Return Me.m_background
End Get
End Property
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
Public ReadOnly Property Foreground() As ItemLayoutColors
Get
Return Me.m_foreground
End Get
End Property
Private m_background As ItemLayoutColors
Private m_foreground As ItemLayoutColors
Private m_listBox As UIListBox
End Class
<ToolboxItem(False)>
Public Class ItemLayoutColors
Inherits Component
Public Sub New(layout As ItemLayout)
If (layout Is Nothing) Then Throw New ArgumentNullException("layout")
Me.m_layout = layout
End Sub
Friend ReadOnly Property Layout() As ItemLayout
Get
Return Me.m_layout
End Get
End Property
Public Property Selected() As Color
Get
Return Me.m_selected
End Get
Set(value As Color)
If (value <> Me.m_selected) Then
Me.m_selected = value
Me.Layout.ListBox.NotifyStateChanged(Me, "Selected")
End If
End Set
End Property
Public Property Unselected() As Color
Get
Return Me.m_unselected
End Get
Set(value As Color)
If (value <> Me.m_unselected) Then
Me.m_unselected = value
Me.Layout.ListBox.NotifyStateChanged(Me, "Unselected")
End If
End Set
End Property
Private Function ShouldSerializeSelected() As Boolean
Return (Me.Selected <> Color.Empty)
End Function
Private Function ShouldSerializeUnselected() As Boolean
Return (Me.Unselected <> Color.Empty)
End Function
Private m_selected As Color
Private m_unselected As Color
Private m_layout As ItemLayout
End Class
Файл конструктора
Me.UiListBox1.StateDisabled.Background.Selected = System.Drawing.Color.Red
UiListBox1.StateEnabled.Background.Selected = Color.Black
, я не понимаю, как реализовать Setter
таким образом, также, когда свойство обновляется, я должен сделать элемент управления недействительным (я Я делаю это из Setter
в приведенном выше примере кода), но из этих классов я не могу получить доступ к базовому классу для аннулирования, не могли бы вы расширить пример, пожалуйста?
Public Property StateEnabled() As ItemLayout Get Return Me.m_stateEnabled End Get Set(value As ItemLayout) Me.m_stateEnabled = value MyBase.Invalidate MyBase.Visible = False ' just trying to set a random control's property End Set End Property
TypeConverter
не так страшен, как кажется: во-первых, объявления свойств ListBox:
Public Class ListBoxEx
Inherits ListBox
<Browsable(True), EditorBrowsable(EditorBrowsableState.Always),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
Public Property SelectedItemColor As ItemStateColors
<Browsable(True), EditorBrowsable(EditorBrowsableState.Always),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
DefaultValue(-1)>
Public Property UnSelectedItemColor As ItemStateColors
Public Sub New()
' they are Objects, be sure to instance them!
' VERY important!
SelectedItemColor = New ItemStateColors
UnSelectedItemColor = New ItemStateColors
End Sub
end class
Затем определите класс ItemStateColors
:
<TypeConverter(GetType(ItemStateConverter))>
Public Class ItemStateColors
<Browsable(True), NotifyParentProperty(True),
EditorBrowsable(EditorBrowsableState.Always), DefaultValue(GetType(Color), "")>
Public Property EnabledBackColor As Color
<Browsable(True), NotifyParentProperty(True),
EditorBrowsable(EditorBrowsableState.Always), DefaultValue(GetType(Color), "")>
Public Property DisabledBackColor As Color
Public Sub New()
' default values, if any
EnabledBackColor = SystemColors.Window
DisabledBackColor = SystemColors.Control
End Sub
End Class
Каждый из ваших свойств ItemState
является экземпляром этого класса. Обратите внимание, что Type
включает атрибут TypeConverter
- это обеспечивает "волшебство". Ours предоставит возможность expando AND преобразует содержимое для отображения в сетке свойств:
Public Class ItemStateConverter
Inherits ExpandableObjectConverter
Public Overrides Function ConvertTo(context As ITypeDescriptorContext,
culture As Globalization.CultureInfo,
value As Object, destinationType As Type) As Object
If destinationType Is GetType(String) Then
Dim item As ItemStateColors = CType(value, ItemStateColors)
' ToDo: decide the format of collapsed info
Return String.Format("{0}, {1}", item.EnabledBackColor.ToString,
item.DisabledBackColor.ToString)
End If
Return MyBase.ConvertTo(context, culture, value, destinationType)
End Function
End Class
Component
метод проще реализовать, но TypeConverter
позволяет вам управлять тем, что отображается, когда свойство TypeConverter
:
Одной из функций, которые обычно выполняет TypeConverter, является код для сериализации/десериализации типов для дизайнера. Это не нужно здесь, потому что Type - это просто Color
который VS/NET знает, как это сделать. Что он делает в этом случае:
- пометить свойство как расширяемое
- предоставлять информацию "Сводка", когда имущество рушится
Другая вещь, в которой вы нуждаетесь, - это когда вы вставляете один тип в другой (как в myControl.StateEnabled.SelectedItem.ForeColor
). TypeConverter
их так, вам понадобится TypeConverter
или какое-нибудь решение кода, такое как ссылка на экземпляр (и я никогда не могу сказать, какие элементы ваших вопросов являются обязательными). VS только знает, чтобы сверлить в первый слой, вам придется предоставить TypeConverter
для детализации, чтобы получить данные о цвете. Однако SelectedItem
, DeselectedItem
и ReadOnlyItem
могут использовать один и тот же TypeConverter
.
Тип Foo, который наследуется от Component, также поставляет пустой снимок.
Смотрите также:
ExpandableObjectConverter
Практическое руководство. Внедрение конвертера типов
Заключительное примечание: все ваши сеттеры Prop должны тестировать пройденное значение и отклонять Color.Transparent
.
Используется ли для этого атрибут [Category]
?
FooBar As Point
и посмотрите). В противном случае вам, возможно, придется написать свой собственный UITypeEditor и / или TypeConverter. (обратите внимание, что в связанной статье все стандартные типы: Расположение, Шрифт. Размер). Иногда вы можете предоставить достаточно информации в TypeConverter, чтобы он работал автоматически.