为Avalonia应用自动生成StyledProperty和DirectProperty
<p>最近学习了源生成器,遂仿照CommunityToolkit/Windows中的DependencyPropertyGenerator写了个生成器,可自动生成Avalonia中的<code>StyledProperty</code>和<code>DirectProperty</code></p><p>NuGet:https://www.nuget.org/packages/PropertyGenerator.Avalonia<br>
Github:https://github.com/zxbmmmmmmmmm/PropertyGenerator</p>
<h2 id="先决条件">先决条件</h2>
<p>Avalonia版本:≥ 11.3.0</p>
<p>由于使用了<code>field</code>关键字和部分属性,需要在项目文件内将<code>LangVersion</code>设置为<code>preview</code></p>
<h2 id="styledproperty">StyledProperty</h2>
<p>在需要生成<code>StyledProperty</code>的部分属性上添加<code>GeneratedStyledProperty</code>特性即可</p>
<pre><code class="language-csharp">
public partial int Count { get; set; }
</code></pre>
<p>生成的代码:</p>
<pre><code class="language-csharp">StyledProperty<int> CountProperty = AvaloniaProperty.Register<MainWindow, int>(name: nameof(Count));
public partial int Count { get => GetValue(CountProperty); set => SetValue(CountProperty, value); }
</code></pre>
<hr>
<p><code>StyledProperty</code>不支持直接设置默认值,需要使用以下写法</p>
<pre><code class="language-csharp">
public partial int Count { get; set; }
</code></pre>
<p>生成的代码:</p>
<pre><code class="language-csharp">Avalonia.StyledProperty<int> CountProperty = AvaloniaProperty.Register<MainWindow, int>(name: nameof(Count), defaultValue: 10);
public partial int Count { get => GetValue(CountProperty); set => SetValue(CountProperty, value); }
</code></pre>
<hr>
<p>StyledProperty的所有功能都被支持(仅作展示)</p>
<pre><code class="language-csharp">[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;
}
</code></pre>
<p>生成的代码:</p>
<pre><code class="language-csharp">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); }
</code></pre>
<h2 id="directproperty">DirectProperty</h2>
<p>和<code>GeneratedStyledProperty</code>的写法相似:</p>
<pre><code class="language-csharp">
public partial IEnumerable? Items { get; set; }
</code></pre>
<hr>
<p><code>DirectProperty</code>可以被直接初始化</p>
<pre><code class="language-csharp">
public partial IEnumerable? Items { get; set; } = new AvaloniaList<object>();
</code></pre>
<hr>
<p>支持自定义<code>DirectProperty</code>的 <code>Getter</code> 和<code>Setter</code></p>
<pre><code class="language-csharp">
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;
</code></pre>
<p>生成的代码:</p>
<pre><code class="language-csharp">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); }
</code></pre>
<h2 id="onpropertychanged">OnPropertyChanged</h2>
<p>使用<code>GeneratedStyledProperty</code>或者<code>GeneratedDirectProperty</code>时,会自动生成部分方法用以通知属性更改</p>
<pre><code class="language-csharp">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;
}
}
</code></pre>
<p>可以直接使用这些方法直接处理属性的变化:</p>
<pre><code class="language-csharp">partial void OnCountPropertyChanged(int newValue)
{
// 处理属性变化...
}
</code></pre>
<p>如果代码已重写<code>OnPropertyChanged</code>并包含其他逻辑,则可以通过<code>DoNotGenerateOnPropertyChanged</code>特性关闭此功能:</p>
<pre><code class="language-csharp">
public partial class MainWindow : Window
{ ... }
</code></pre>
<p>也可以在整个程序集上禁用此功能</p>
<pre><code class="language-csharp">
</code></pre><br><br>
来源:https://www.cnblogs.com/BettaFish/p/19027678
頁:
[1]