List Properties names into a variable by Category Attribute

267 views Asked by At

I am trying to list some properties names by Category attribute and put them into a variable.
For example, to get all properties names which "belong" to category Appearance and put them into a variable.

I have a similar example which resets specific properties, but I have to add them one by one which I want to avoid.

Dim _Form As Form = CType(Me, Form)
Dim ListOfPropertyNames As New List(Of String) From {"BackColor", "ForeColor"}
For Each _Property In ListOfPropertyNames
    Dim _PropertyDescriptor As PropertyDescriptor = TypeDescriptor.GetProperties(_Form)(_Property)
    If _PropertyDescriptor.CanResetValue(_Form) Then
        If _PropertyDescriptor.GetValue(_Form) IsNot Nothing Then
            _PropertyDescriptor.ResetValue(_Form)
        End If
    End If
Next
1

There are 1 answers

4
Jimi On BEST ANSWER

There are four possible scenarios in your question (that I can think of):

  1. (More probable) Get the List of Properties ordered by Category and DisplayName and, if the PropertyDescriptor.CanResetValue() method returns a positive result, reset the Property.
    Eventually, filter by Category inserting a .Where clause.

  2. Get the List of Properties which belong to some pre-defined Categories and reset all the Properties that have a value different from the DefaultValueAttribute, checking the PropertyDescriptor.CanResetValue() method result.

  3. Same as above, but also adding a list of specific Properties to reset.

  4. Get the List of Properties which belong to some pre-defined Categories and reset all the Properties no matter what PropertyDescriptor.CanResetValue() thinks about it.

First case scenario:
Using LINQ, query the TypeDescriptor to build a list of PropertyDescriptor elements ordered by Category and DisplayName.
Check PropertyDescriptor.CanResetValue() result and reset the Property value to its default if it has changed.

Dim PropertyCollection As List(Of PropertyDescriptor) = TypeDescriptor.
                                                        GetProperties(_Form).
                                                        OfType(Of PropertyDescriptor).
                                                        OrderBy(Function(item) item.Category).
                                                        ThenBy(Function(item) item.DisplayName).
                                                        ToList()

For Each _PropertyDescriptor As PropertyDescriptor In PropertyCollection
    If _PropertyDescriptor.CanResetValue(_Form) Then
        If _PropertyDescriptor.GetValue(_Form) IsNot Nothing Then
            _PropertyDescriptor.ResetValue(_Form)
        End If
    End If
Next

The same with a Category filter:

Dim PropertyCollection As List(Of PropertyDescriptor) = TypeDescriptor.
                                                        GetProperties(_Form).
                                                        OfType(Of PropertyDescriptor).
                                                        OrderBy(Function(item) item.Category).
                                                        ThenBy(Function(item) item.DisplayName).
                                                        Where(Function(item) item.Category = "Appearance").
                                                        ToList()

The same, grouping the Properties list by Category using GroupBy():

Dim _Form As Form = Me

Dim PropertyCollection As List(Of IGrouping(Of String, PropertyDescriptor)) = TypeDescriptor.
                                  GetProperties(_Form).
                                  OfType(Of PropertyDescriptor).
                                  OrderBy(Function(item) item.Category).
                                  ThenBy(Function(item) item.DisplayName).
                                  GroupBy(Function(item) item.Category).
                                  ToList()

'Extract one Category. It could also be a second For Each loop.
Dim CategoryPropertyList As List(Of PropertyDescriptor) = PropertyCollection.
                                                          SelectMany(Function(grp) grp).
                                                          Where(Function(prop) prop.Category = "Appearance").
                                                          ToList()

For Each _PropertyDescriptor As PropertyDescriptor In CategoryPropertyList

    If _PropertyDescriptor.CanResetValue(_Form) Then
        If _PropertyDescriptor.GetValue(_Form) IsNot Nothing Then
            _PropertyDescriptor.ResetValue(_Form)
        End If
    End If
Next

Second case scenario:
Using LINQ, query the TypeDescriptor to build a list of PropertyDescriptor elements related to a predefined Category list.
Check PropertyDescriptor.CanResetValue() result and reset the Property value to its default if it has changed.

Dim _Form As Form = CType(Me, Form)
Dim ListOfCategoryNames As New List(Of String) From {"Appearance", "Behavior"}

For Each Category As String In ListOfCategoryNames
    Dim _PropertyCollection As List(Of PropertyDescriptor) = TypeDescriptor.
                                                             GetProperties(_Form).
                                                             OfType(Of PropertyDescriptor).
                                                             Where(Function(item) item.Category = Category).
                                                             ToList()

    For Each _PropertyDescriptor As PropertyDescriptor In _PropertyCollection
        If _PropertyDescriptor.CanResetValue(_Form) Then
            If _PropertyDescriptor.GetValue(_Form) IsNot Nothing Then
                _PropertyDescriptor.ResetValue(_Form)
            End If
        End If
    Next
Next

Third case scenario:
Same as above, but add a filter for some specific properties:

Dim ListOfCategoryNames As New List(Of String) From {"Appearance", "Behavior"}
Dim ListOfPropertyNames As New List(Of String) From {"BackColor", "ForeColor", "AllowDrop", "Enabled"}

For Each Category As String In ListOfCategoryNames
    For Each PropertyName As String In ListOfPropertyNames
        Dim _PropertyDescriptor As PropertyDescriptor = TypeDescriptor.GetProperties(_Form).
                                                        OfType(Of PropertyDescriptor).
                                                        Where(Function(item) item.Category = Category AndAlso
                                                                             item.Name = PropertyName).
                                                        FirstOrDefault()

        If (_PropertyDescriptor IsNot Nothing) AndAlso _PropertyDescriptor.CanResetValue(_Form) Then
            If _PropertyDescriptor.GetValue(_Form) IsNot Nothing Then
                _PropertyDescriptor.ResetValue(_Form)
            End If
        End If
    Next
Next

Fourth case scenario:
Using LINQ, query the TypeDescriptor to build a list of PropertyDescriptor elements related to a predefined Category list.
Check whether the DefaultValueAttribute of a Property is Nothing, because if it is, PropertyDescriptor.CanResetValue() will skip it and look for a custom method alternative to get the result. Since no such methods are definined here, it will always return false unless it can detect that a Property has been changed.
If no DefaultValueAttribute is present, or PropertyDescriptor.CanResetValue() returns True, resets all Properties values to Default, checking beforehand that a ResetValue() method exists for the Property.

Dim _Form As Form = CType(Me, Form)
Dim ListOfCategoryNames As New List(Of String) From {"Appearance", "Behavior"}

For Each Category As String In ListOfCategoryNames
    Dim _PropertyCollection As List(Of PropertyDescriptor) = TypeDescriptor.
                                                             GetProperties(_Form).
                                                             OfType(Of PropertyDescriptor).
                                                             Where(Function(item) item.Category = Category).
                                                             ToList()

    For Each _PropertyDescriptor As PropertyDescriptor In _PropertyCollection
        Dim _DefaultAttribute As DefaultValueAttribute = _PropertyDescriptor.
                                                         Attributes.OfType(Of DefaultValueAttribute).
                                                         Where(Function(item) item.IsDefaultAttribute).
                                                         FirstOrDefault

        If (_DefaultAttribute Is Nothing) Or (_PropertyDescriptor.CanResetValue(_Form)) Then
            If _PropertyDescriptor.GetType().GetMethod("ResetValue", BindingFlags.Public Or BindingFlags.Instance) IsNot Nothing Then
                If _PropertyDescriptor.GetValue(_Form) IsNot Nothing Then
                    _PropertyDescriptor.ResetValue(_Form)
                End If
            End If
        End If
    Next
Next