diff --git a/README.md b/README.md index 0a69023509..f2ae1db0e5 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,7 @@ [![NuGet Stats](https://img.shields.io/nuget/v/XamlNameReferenceGenerator.svg)](https://www.nuget.org/packages/XamlNameReferenceGenerator) [![downloads](https://img.shields.io/nuget/dt/XamlNameReferenceGenerator)](https://www.nuget.org/packages/XamlNameReferenceGenerator) ![Build](https://github.com/avaloniaui/Avalonia.NameGenerator/workflows/Build/badge.svg) ![License](https://img.shields.io/github/license/avaloniaui/Avalonia.NameGenerator.svg) ![Size](https://img.shields.io/github/repo-size/avaloniaui/Avalonia.NameGenerator.svg) -> **Warning** This tool hasn't been extensively tested, so use at your own risk. - ### C# `SourceGenerator` for Typed Avalonia `x:Name` References - - This is a [C# `SourceGenerator`](https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/) built for generating strongly-typed references to controls with `x:Name` (or just `Name`) attributes declared in XAML (or, in `.axaml`). The source generator will look for the `xaml` (or `axaml`) file with the same name as your partial C# class that is a subclass of `Avalonia.INamed` and parses the XAML markup, finds all XAML tags with `x:Name` attributes and generates the C# code. ### Getting Started @@ -20,9 +16,8 @@ Or, if you are using [submodules](https://git-scm.com/docs/git-submodule), you c ```xml - + +### Why do I need this? + +The typed `x:Name` references might be useful if you decide to use e.g. [ReactiveUI code-behind bindings](https://www.reactiveui.net/docs/handbook/data-binding/): + +```cs +// UserNameValidation and PasswordValidation are auto generated. +public partial class SignUpView : ReactiveWindow +{ + public SignUpView() + { + AvaloniaXamlLoader.Load(this); + this.WhenActivated(disposables => + { + this.BindValidation(ViewModel, x => x.UserName, x => x.UserNameValidation.Text) + .DisposeWith(disposables); + this.BindValidation(ViewModel, x => x.Password, x => x.PasswordValidation.Text) + .DisposeWith(disposables); + }); + } +} +``` + +### Advanced Usage + +The `x:Name` generator can be configured via MsBuild properties that you can put into your C# project file (`.csproj`). Using such options, you can configure the generator behavior, the default field modifier, namespace and path filters. The generator supports the following options: + +- `AvaloniaNameGeneratorBehavior` + Possible values: `OnlyProperties`, `InitializeComponent` + Determines if the generator should generate get-only properties, or the `InitializeComponent` method. + +- `AvaloniaNameGeneratorDefaultFieldModifier` + Possible values: `internal`, `public`, `private`, `protected` + The default field modifier that should be used when there is no `x:FieldModifier` directive specified. + +- `AvaloniaNameGeneratorFilterByPath` + Posssible format: `glob_pattern`, `glob_pattern;glob_pattern` + The generator will process only XAML files with paths matching the specified glob pattern(s). + Example: `*/Views/*View.xaml`, `*View.axaml;*Control.axaml` + +- `AvaloniaNameGeneratorFilterByNamespace` + Posssible format: `glob_pattern`, `glob_pattern;glob_pattern` + The generator will process only XAML files with base classes' namespaces matching the specified glob pattern(s). + Example: `MyApp.Presentation.*`, `MyApp.Presentation.Views;MyApp.Presentation.Controls` + +The default values are given by: + +```xml + + + OnlyProperties + internal + * + * + + + +``` + +![](https://user-images.githubusercontent.com/6759207/107812261-7ddfea00-6d80-11eb-9c7e-67bf95d0f0d4.gif) + ### What do the generated sources look like? -For the [`SignUpView` view class](https://github.com/avaloniaui/Avalonia.NameGenerator/blob/main/src/Avalonia.NameGenerator.Sandbox/Views/SignUpView.xaml) from [the sandbox project](https://github.com/avaloniaui/Avalonia.NameGenerator/tree/main/Avalonia.NameGenerator.Sandbox), we get the following generated output: +For [`SignUpView`](https://github.com/avaloniaui/Avalonia.NameGenerator/blob/main/src/Avalonia.NameGenerator.Sandbox/Views/SignUpView.xaml), we get the following generated output when the source generator is in the `OnlyProperties` mode: ```cs // @@ -87,25 +142,45 @@ namespace Avalonia.NameGenerator.Sandbox.Views } ``` -### Why do I need this? - -The typed `x:Name` references might be useful if you decide to use e.g. [ReactiveUI code-behind bindings](https://www.reactiveui.net/docs/handbook/data-binding/): +If you enable the `InitializeComponent` source generator mode, you get: ```cs -// UserNameValidation and PasswordValidation are auto generated. -public partial class SignUpView : ReactiveWindow +// + +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Sample.App { - public SignUpView() + partial class SampleView { - AvaloniaXamlLoader.Load(this); - this.WhenActivated(disposables => + internal global::Avalonia.NameGenerator.Sandbox.Controls.CustomTextBox UserNameTextBox { get; set; } + public global::Avalonia.Controls.TextBlock UserNameValidation { get; set; } + private global::Avalonia.Controls.TextBox PasswordTextBox { get; set; } + internal global::Avalonia.Controls.TextBlock PasswordValidation { get; set; } + internal global::Avalonia.Controls.ListBox AwesomeListView { get; set; } + internal global::Avalonia.Controls.TextBox ConfirmPasswordTextBox { get; set; } + internal global::Avalonia.Controls.TextBlock ConfirmPasswordValidation { get; set; } + internal global::Avalonia.Controls.Button SignUpButton { get; set; } + internal global::Avalonia.Controls.TextBlock CompoundValidation { get; set; } + + public void InitializeComponent(bool loadXaml = true) { - this.BindValidation(ViewModel, x => x.UserName, x => x.UserNameValidation.Text) - .DisposeWith(disposables); - this.BindValidation(ViewModel, x => x.Password, x => x.PasswordValidation.Text) - .DisposeWith(disposables); - }); + if (loadXaml) + { + AvaloniaXamlLoader.Load(this); + } + + UserNameTextBox = this.FindControl("UserNameTextBox"); + UserNameValidation = this.FindControl("UserNameValidation"); + PasswordTextBox = this.FindControl("PasswordTextBox"); + PasswordValidation = this.FindControl("PasswordValidation"); + AwesomeListView = this.FindControl("AwesomeListView"); + ConfirmPasswordTextBox = this.FindControl("ConfirmPasswordTextBox"); + ConfirmPasswordValidation = this.FindControl("ConfirmPasswordValidation"); + SignUpButton = this.FindControl("SignUpButton"); + CompoundValidation = this.FindControl("CompoundValidation"); + } } } ``` - diff --git a/src/Avalonia.NameGenerator/GeneratorOptions.cs b/src/Avalonia.NameGenerator/GeneratorOptions.cs index dd4d8834f8..1a92e103d5 100644 --- a/src/Avalonia.NameGenerator/GeneratorOptions.cs +++ b/src/Avalonia.NameGenerator/GeneratorOptions.cs @@ -8,7 +8,7 @@ namespace Avalonia.NameGenerator AvaloniaNameGeneratorBehavior = 0, AvaloniaNameGeneratorDefaultFieldModifier = 1, AvaloniaNameGeneratorFilterByPath = 2, - AvaloniaNameGeneratorFilterByNamespace = 2, + AvaloniaNameGeneratorFilterByNamespace = 3, } public enum DefaultFieldModifier diff --git a/version.json b/version.json index 3fb9f3880b..101441ba8c 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "0.3.1-preview", + "version": "0.4", "assemblyVersion": { "precision": "revision" },