Set the default value of DesignerSerializationVisi

2020-04-20 21:15发布

问题:

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

回答1:

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; }
}