Создать расширяемую группу в сетке свойств?

1

СЦЕНАРИЙ

Я подклассифицировал ListBox и я добавил свойства цвета, когда мой элемент управления включен, отключен или в режиме ReadOnly:

Изображение 174551

ВОПРОС

В С# или VB.Net, что мне нужно сделать, чтобы упорядочить свойства в сетке свойств в расширяемые группы с помощью этой структуры?:

[+] State Enabled

  [+] Selected Item
      · BackColor
      · ForeColor

  [+] Unselected Item
      · BackColor
      · ForeColor

Это визуальный пример, взятый из пользовательского элемента управления Krypton lib, который демонстрирует, что я хотел бы подражать:

Изображение 174551

ОБНОВИТЬ

Я думаю, что в этом 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
  • 0
    Это не просто косметическая вещь. Во-первых, он опирается на тип, и вы, вероятно, определили его как цвет. Во-вторых, если тип является стандартным, например, Size или Point, VS сделает это автоматически (определите новую опору FooBar As Point и посмотрите). В противном случае вам, возможно, придется написать свой собственный UITypeEditor и / или TypeConverter. (обратите внимание, что в связанной статье все стандартные типы: Расположение, Шрифт. Размер). Иногда вы можете предоставить достаточно информации в TypeConverter, чтобы он работал автоматически.
Теги:
visual-studio
winforms
user-controls

3 ответа

1
Лучший ответ

Первое, что вам нужно сделать, это структурировать ваши свойства в классы. Затем вам нужно создать настраиваемый конвертер типов для каждого класса, чтобы он стал сериализуемым. Однако есть более простой способ добиться этого; наследует класс 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

Изображение 174551

Файл конструктора

Me.UiListBox1.StateDisabled.Background.Selected = System.Drawing.Color.Red
  • 0
    Спасибо за пример, но я вообще не понимал, как его использовать. Как предполагается, что я могу обновлять значения во время выполнения? например, я не могу сделать это: UiListBox1.StateEnabled.Background.Selected = Color.Black , я не понимаю, как реализовать Setter таким образом, также, когда свойство обновляется, я должен сделать элемент управления недействительным (я Я делаю это из Setter в приведенном выше примере кода), но из этих классов я не могу получить доступ к базовому классу для аннулирования, не могли бы вы расширить пример, пожалуйста?
  • 0
    Это то, что я пробовал с любым результатом: 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
Показать ещё 2 комментария
2

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:

Изображение 174551


Одной из функций, которые обычно выполняет TypeConverter, является код для сериализации/десериализации типов для дизайнера. Это не нужно здесь, потому что Type - это просто Color который VS/NET знает, как это сделать. Что он делает в этом случае:
- пометить свойство как расширяемое
- предоставлять информацию "Сводка", когда имущество рушится

Другая вещь, в которой вы нуждаетесь, - это когда вы вставляете один тип в другой (как в myControl.StateEnabled.SelectedItem.ForeColor). TypeConverter их так, вам понадобится TypeConverter или какое-нибудь решение кода, такое как ссылка на экземпляр (и я никогда не могу сказать, какие элементы ваших вопросов являются обязательными). VS только знает, чтобы сверлить в первый слой, вам придется предоставить TypeConverter для детализации, чтобы получить данные о цвете. Однако SelectedItem, DeselectedItem и ReadOnlyItem могут использовать один и тот же TypeConverter.

Изображение 174551

Тип Foo, который наследуется от Component, также поставляет пустой снимок.

Смотрите также:

ExpandableObjectConverter
Практическое руководство. Внедрение конвертера типов


Заключительное примечание: все ваши сеттеры Prop должны тестировать пройденное значение и отклонять Color.Transparent.

  • 0
    Я видел этот ответ слишком поздно, я постараюсь, спасибо!
  • 0
    Интересно, если бы вы могли объяснить, как вы добавили на изображении «SelectedItemColor» в группу «Electro», я не могу найти способ сделать это
1

Используется ли для этого атрибут [Category]?

пример

  • 0
    Спасибо, но атрибут Category работает только в том случае, если свойства отсортированы по категориям (по категориям), а не тогда, когда они отсортированы в алфавитном порядке в сетке свойств.
  • 0
    Приведенный вами пример объясняет вещь, которая полностью отличается от того, что вы предложили, и кажется, что реализовать такую вещь крайне сложно, по моему мнению, не похоже, что образ криптона, которым я поделился в моем Вопрос использует данные коллекции для создания групп, потому что он не предоставляет никакой кнопки для редактирования содержимого коллекции, как показано на рисунке 5 примера, который вы предоставили, тогда я действительно надеюсь, что это можно сделать проще. Спасибо за Ваш ответ.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню