Registering Custom Attributes

This tutorial demonstrates how to register a custom attribute with the Visual Designer using SomeAttribute as an example. By default, custom attributes do not appear in the Attribute Editor, so we need to register them explicitly. We’ll also use OdinDesignerBinding to make SomeAttribute’s properties editable and ensure they are serialized by the designer.

[AttributeUsage(AttributeTargets.Field)]
public class SomeAttribute : Attribute
{
    public Color FieldColor;

    public string SomeProperty { get; set; }
    
    public int SomeSpecialProperty 
    {
        get => this.SomeSpecialPropertyValue;

        set 
        {
            this.SomeSpecialPropertyIsSet = true;
            this.SomeSpecialPropertyValue = value;
        }
    }
    
    internal int SomeSpecialPropertyValue;
    internal bool SomeSpecialPropertyIsSet;
}

First we will register the attribute in the Visual Designer using OdinVisualDesignerAttributeItem:

[assembly: OdinVisualDesignerAttributeItem("Custom", typeof(SomeAttribute))]

[AttributeUsage(AttributeTargets.Field)]
public class SomeAttribute : Attribute
{
    ...
}
Image displaying our registered attribute in the Attribute Editor
The Visual Designer now knows about our attribute.

By default, the Visual Designer does not serialize properties. To make a property serializable, use OdinDesignerBinding. This attribute tells the designer which fields or internal values represent the property’s state, so they get saved correctly.

[AttributeUsage(AttributeTargets.Field)]
public class SomeAttribute : Attribute
{
    public Color FieldColor;

    [OdinDesignerBinding(nameof(SomeProperty))]
    public string SomeProperty { get; set; }

    [OdinDesignerBinding(nameof(SomeSpecialPropertyIsSet), nameof(SomeSpecialPropertyValue))]
    public int SomeSpecialProperty 
    {
        get => this.SomeSpecialPropertyValue;
        set 
        {
            this.SomeSpecialPropertyIsSet = true;
            this.SomeSpecialPropertyValue = value;
        }
    }

    internal int SomeSpecialPropertyValue;
    internal bool SomeSpecialPropertyIsSet;
}
  • SomeProperty: Serialized directly.
  • SomeSpecialProperty: Both SomeSpecialPropertyValue and SomeSpecialPropertyIsSet are serialized because the property depends on them.