Skip to content

lucdem/AvaSourceGenerators

Repository files navigation

AvaSourceGenerators

Source generators for AvaloniaUI boilerplate code.

Example

To use it, simply declare a class as partial and annotate a field with the AvaStyledProperty attribute to generate a StyledProperty, or the AvaDirectProperty to generate a DirectProperty. For example:

using Avalonia.Controls.Primitives;
using Lucdem.Avalonia.SourceGenerators.Attributes;

namespace Lucdem.Avalonia.SourceGenerators.Sample.Controls;

public partial class LabeledButton : TemplatedControl
{
    public LabeledButton() { }

    [AvaStyledProperty]
    private string labelText = string.Empty;
}

The source generator will detect the attribute annotated field and create another partial class declaration with the basic StyledProperty boilerplate:

public static readonly StyledProperty<string> LabelTextProperty = AvaloniaProperty.Register<LabeledButton, string>("LabelText");

public string LabelText 
{ 
	get => GetValue(LabelTextProperty);
	set => SetValue(LabelTextProperty, value);
}

Well, or something equivalent to that at least. The exact output of the code generator is not exactly made for human eyes:

// <auto-generated/>
#pragma warning disable
#nullable enable
namespace Lucdem.Avalonia.SourceGenerators.Sample.Controls
{
    /// <inheritdoc/>
    partial class LabeledButton
    {
        public static readonly global::Avalonia.StyledProperty<string> LabelTextProperty = global::Avalonia.AvaloniaProperty.Register<LabeledButton, string>("LabelText");
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        [global::System.CodeDom.Compiler.GeneratedCode("Lucdem.Avalonia.SourceGenerators.Generators.StyledPropertyGenerator", "0.1.0.0")]
        public string LabelText { get => GetValue(LabelTextProperty); set => SetValue(LabelTextProperty, value); }
    }
}

The same goes for DirectProperties, the following code:

using Avalonia.Controls.Primitives;
using Lucdem.Avalonia.SourceGenerators.Attributes;

namespace Lucdem.Avalonia.SourceGenerators.Sample.Controls;

public partial class SliderWithValueBox : TemplatedControl
{
    [AvaDirectProperty]
    private double _value = 25;
}

Will trigger the source generator to create this partial declaration:

// <auto-generated/>
#pragma warning disable
#nullable enable
namespace Lucdem.Avalonia.SourceGenerators.Sample.Controls
{
    /// <inheritdoc/>
    partial class SliderWithValueBox
    {
        public static readonly global::Avalonia.DirectProperty<SliderWithValueBox, double> ValueProperty = global::Avalonia.AvaloniaProperty.RegisterDirect<SliderWithValueBox, double>("Value", o => o.Value, (o, v) => o.Value = v);
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        [global::System.CodeDom.Compiler.GeneratedCode("Lucdem.Avalonia.SourceGenerators.Generators.DirectPropertyGenerator", "0.1.1.2")]
        public double Value { get => _value; set => SetAndRaise(ValueProperty, ref _value, value); }
    }
}

How to use

The project is available as a nuget package.

How to inspect generated source code in VisualStudio or Rider

After referencing the nuget package in your project:

In VisualStudio, go to {YourProject}->Dependencies->Analyzers->Lucdem.Avalonia.SourceGenerators->{NameOfTheGenerator}.

In Rider, go to {YourProject}->Dependencies->Source Generators->{NameOfTheGenerator}.

TODO list

  • Add Diagnostics (warn user that the class should inherit from AvaloniaObject, that the annotated field must start with lower case character, etc)
  • Add generators for attached properties
  • Maybe use field value as the default value for the property?
  • Add a way to mark a function as the validation function for a property (something like a [AvaPropValidator(nameof(PropertyName))] annotation maybe?)

About

Source generators for AvaloniaUI boilerplate code

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages