为Avalonia应用自动生成StyledProperty和DirectProperty

最近学习了源生成器,遂仿照CommunityToolkit/Windows中的DependencyPropertyGenerator写了个生成器,可自动生成Avalonia中的StyledPropertyDirectProperty

NuGet:https://www.nuget.org/packages/PropertyGenerator.Avalonia
Github:https://github.com/zxbmmmmmmmmm/PropertyGenerator

先决条件

Avalonia版本:≥ 11.3.0

由于使用了field关键字和部分属性,需要在项目文件内将LangVersion设置为preview

StyledProperty

在需要生成StyledProperty的部分属性上添加GeneratedStyledProperty特性即可

[GeneratedStyledProperty]
public partial int Count { get; set; }

生成的代码:

StyledProperty<int> CountProperty = AvaloniaProperty.Register<MainWindow, int>(name: nameof(Count));
public partial int Count { get => GetValue(CountProperty); set => SetValue(CountProperty, value); }

StyledProperty不支持直接设置默认值,需要使用以下写法

[GeneratedStyledProperty(10)]
public partial int Count { get; set; }

生成的代码:

Avalonia.StyledProperty<int> CountProperty = AvaloniaProperty.Register<MainWindow, int>(name: nameof(Count), defaultValue: 10);
public partial int Count { get => GetValue(CountProperty); set => SetValue(CountProperty, value); }

StyledProperty的所有功能都被支持(仅作展示)

[GeneratedStyledProperty(
    DefaultValueCallback = nameof(DefaultValueCallback),
    DefaultValue = true,
    Validate = nameof(Validate),
    Coerce = nameof(Coerce),
    EnableDataValidation = true,
    Inherits = true,
    DefaultBindingMode = BindingMode.TwoWay)]
public partial bool? IsStarted { get; set; }

private static bool DefaultValueCallback()
{
    return true;
}
private static bool Validate(bool? value)
{
    return true;
}
private static bool? Coerce(AvaloniaObject x, bool? y)
{
    return true;
}

生成的代码:

StyledProperty<bool?> IsStartedProperty = AvaloniaProperty.Register<MainWindow, bool?>(
	name: nameof(IsStarted), 
	defaultValue: DefaultValueCallback(), 
	validate: Validate,
	coerce: Coerce, 
	enableDataValidation: true,
	inherits: true, 
	defaultBindingMode:BindingMode.TwoWay);
public partial bool? IsStarted { get => GetValue(IsStartedProperty); set => SetValue(IsStartedProperty, value); }

DirectProperty

GeneratedStyledProperty的写法相似:

[GeneratedDirectProperty]
public partial IEnumerable? Items { get; set; }

DirectProperty可以被直接初始化

[GeneratedDirectProperty]
public partial IEnumerable? Items { get; set; } = new AvaloniaList<object>();

支持自定义DirectPropertyGetterSetter

[GeneratedDirectProperty(Getter = nameof(Getter), Setter = nameof(Setter))]
public partial IEnumerable? Items { get; set; }
public static IEnumerable? Getter(MainWindow o) => o.Items;
public static void Setter(MainWindow o, IEnumerable? v) => o.Items = v;

生成的代码:

public static readonly DirectProperty<MainWindow, IEnumerable?> ItemsProperty
    = AvaloniaProperty.RegisterDirect<MainWindow, IEnumerable?>(
    name: nameof(Items),
    getter: Getter, 
    setter: Setter);

public partial IEnumerable? Items { get => field; set => SetAndRaise(ItemsProperty, ref field, value); }

OnPropertyChanged

使用GeneratedStyledProperty或者GeneratedDirectProperty时,会自动生成部分方法用以通知属性更改

partial void OnCountPropertyChanged(int newValue);
partial void OnCountPropertyChanged(int oldValue, int newValue);
partial void OnCountPropertyChanged(AvaloniaPropertyChangedEventArgs e);

protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
    base.OnPropertyChanged(change);
    switch (change.Property.Name)
    {
        case nameof(Count):
            OnCountPropertyChanged(change);
            OnCountPropertyChanged((int)change.NewValue);
            OnCountPropertyChanged((int)change.OldValue, (int)change.NewValue);
            break;
    }
}

可以直接使用这些方法直接处理属性的变化:

partial void OnCountPropertyChanged(int newValue) 
{ 
    // 处理属性变化...
}

如果代码已重写OnPropertyChanged并包含其他逻辑,则可以通过DoNotGenerateOnPropertyChanged特性关闭此功能:

[DoNotGenerateOnPropertyChanged]
public partial class MainWindow : Window
{ ... }

也可以在整个程序集上禁用此功能

[assembly: DoNotGenerateOnPropertyChanged]

来源链接:https://www.cnblogs.com/BettaFish/p/19027678

© 版权声明
THE END
支持一下吧
点赞14 分享
评论 抢沙发
头像
请文明发言!
提交
头像

昵称

取消
昵称表情代码快捷回复

    暂无评论内容