Set the default value of DesignerSerializationVisibility to hidden
Asked Answered
A

2

1

Is there a way to set the a default value for the attribute DesignerSerializationVisibility for all the properties of a given class?

In practice, a way to switch the default behavior of black-listing the properties with a white-list approach.

Thanks

Abstriction answered 31/3, 2016 at 15:8 Comment(2)
What's the main problem which makes you to think about such solution?Detrition
I have lots of properties in a control class and I want to exclude most of them from the Designer without messing up the code with attributes.Abstriction
D
8

My preferance

You can provide default values for properties in constructor and decorate them using suitable DefaultValue attribute, then the designer will serialize them only if the value of them is different than default value.

Also if you need to make them invisible at design-time, you can simply decorate them using Browsable(false) then they will not be shown at design time.

Also you can check DesignMode in property setter to prevent setting a value for the property at design time and make it a run-time property.

I also answer your question which you need to Not serialize properties that doesn't have DesignerSerializationVisibility attribute.

At least the approach will introduce a really useful feature to you which you may find helpful in the future.

Not serialize properties that doesn't have DesignerSerializationVisibility attribute

A way to switch the default behavior of blacklisting the properties with a white list approach.

As an option you can create a custom type descriptor for your component and using custom property descriptors which it returns, tell the designer to don't serialize properties that doesn't have DesignerSerializationVisibility.

This way when you want the designer serialize a property you should decorate it with DesignerSerializationVisibility attribute with visible as value.

Implemetaion

The designer ask the PropertyDescriptor of a property to decide to serialize the property. If the ShouldSerialize method of the descriptor returns true it serializes the property, otherwise it doesn't serialize the property.

To change this behavior you should override that method. To make the designer to use your property descriptor, you should register a custom TypeDescriptionProvider for your class. The provider should provide a custom TypeDescriptor for your class. The custom type descriptor should return a list of your new PropertyDescriptor which you override that method.

Important Note: To test the implementations, you should restart the visual studio.

TypeDescriptionProvider

Here we create a custom type description provider for our component. Then we will register the provider for our component.

public class MyTypeDescriptionProvider : TypeDescriptionProvider
{
    public MyTypeDescriptionProvider()
       : base(TypeDescriptor.GetProvider(typeof(object))) { }

    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, 
                                                            object instance)
    {
       ICustomTypeDescriptor baseDescriptor = base.GetTypeDescriptor(objectType, instance);
       return new MyTypeDescriptor(baseDescriptor);
    }
}

TypeDescriptor

Here we implement our type descriptor which it's job is returning a list of our custom property descriptors.

public class MyTypeDescriptor : CustomTypeDescriptor
{
    ICustomTypeDescriptor original;
    public MyTypeDescriptor(ICustomTypeDescriptor originalDescriptor)
        : base(originalDescriptor)
    {
        original = originalDescriptor;
    }
    public override PropertyDescriptorCollection GetProperties()
    {
        return this.GetProperties(new Attribute[] { });
    }
    public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        var properties = base.GetProperties(attributes).Cast<PropertyDescriptor>()
                             .Select(p => new MyPropertyDescriptor(p))
                             .ToArray();
        return new PropertyDescriptorCollection(properties);
    }
}

PropertyDescriptor

Here is the implementation of our custom property descriptor. The implementation of most properties and methods is trivial. Only for ShouldSerialize method, we decide based on having DesignerSerializationVisibility

public class MyPropertyDescriptor : PropertyDescriptor
{
    PropertyDescriptor original;
    public MyPropertyDescriptor(PropertyDescriptor originalProperty)
        : base(originalProperty)
    {
        original = originalProperty;
    }

    // Implement other properties and methods simply using return original
    // The implementation is trivial like this one:
    // public override Type ComponentType
    // {
    //     get { return original.ComponentType; }
    // }

    public override bool ShouldSerializeValue(object component)
    {
        if (original.Attributes.OfType<DesignerSerializationVisibilityAttribute>()
                .Count() == 0)
            return false;

        return original.ShouldSerializeValue(component);
    }
}

Component

At last here is the component. As you see in the component code, we decorated a property (white list strategy) to be serialized. All other properties will not serialize because it's new behavior which we attached to our properties.

[TypeDescriptionProvider(typeof(MyTypeDescriptionProvider))]
public class MyCustomClass : Component
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public string Property3 { get; set; }
}
Detrition answered 31/3, 2016 at 22:56 Comment(3)
Let me know if you have any question about the answer.Detrition
Thanks, a really helpful response... :)Abstriction
For learning purpose, you can also override Attributes property of PropertyDescriptor and check if the property doesn't have a DesignerSerializationVisibility attribute attached, then you add an instance of the attribute with value of DesignerSerializationVisibility.None to the attributes of property.Detrition
P
0

To further extend @RezaAghaei's excellent answer, I replaced ShouldSerializeValue with the below (apols for vb.net):

 Public Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean
    
    Dim c = TypeDescriptor.GetAttributes(component)
    For Each a In c
        If a.TypeId.Name = "NoSerializationPropsAttribute" Then
            Dim attr As NoSerializationPropsAttribute = a
            If attr.PropNames.Contains(Me.Name) Then
                Return False
            End If
        End If
    Next
    Return True

End Function

This lets me decorate the class with the props I want to mask out of deserialization, and therefore skip the need of decorating each property.

    <NoSerializationProps(PropNames:={"DisabledColor", "SelectedColor", "LostFocusColor"})>

One could easily flip it to a WhiteList instead.

Public Class NoSerializationPropsAttribute
    Inherits Attribute

    Public Overridable Property PropNames As String() = {}
End Class

Now if someone could point me to a way of overriding IsBrowsable in the PropertyDescriptor it would be awesome.

Pamphleteer answered 5/4, 2022 at 22:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.