Source generators for AvaloniaUI boilerplate code.
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); }
}
}
The project is available as a nuget package.
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}.
- 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?)