vb.netwinformstypedescriptor

List Properties names into a variable by Category Attribute


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

Solution

  • 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