Git Product home page Git Product logo

avalonia.namegenerator's Introduction

NuGet Stats downloads Build License Size

C# SourceGenerator for Typed Avalonia x:Name References

This is a C# SourceGenerator 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

In order to get started, just install the NuGet package:

dotnet add package XamlNameReferenceGenerator

Or, if you are using submodules, you can reference the generator as such:

<ItemGroup>
    <!-- Remember to ensure XAML files are included via <AdditionalFiles>,
         otherwise C# source generator won't see XAML files. -->
    <AdditionalFiles Include="**\*.xaml"/>
    <ProjectReference Include="..\Avalonia.NameGenerator\Avalonia.NameGenerator.csproj"
                      OutputItemType="Analyzer"
                      ReferenceOutputAssembly="false" />
</ItemGroup>

Usage

After installing the NuGet package, declare your view class as partial. Typed C# references to Avalonia controls declared in XAML files will be generated for classes referenced by the x:Class directive in XAML files. For example, for the following XAML markup:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="Sample.App.SignUpView">
    <TextBox x:Name="UserNameTextBox" x:FieldModifier="public" />
</Window>

A new C# partial class named SignUpView with a single public property named UserNameTextBox of type TextBox will be generated in the Sample.App namespace. We won't see the generated file, but we'll be able to access the generated property as shown below:

using Avalonia.Controls;

namespace Sample.App
{
    public partial class SignUpView : Window
    {
        public SignUpView()
        {
            // This method is generated. Call it before accessing any
            // of the generated properties. The 'UserNameTextBox'
            // property is also generated.
            InitializeComponent();
            UserNameTextBox.Text = "Joseph";
        }
    }
}

Why do I need this?

The typed x:Name references might be useful if you decide to use e.g. ReactiveUI code-behind bindings:

// UserNameValidation and PasswordValidation are auto generated.
public partial class SignUpView : ReactiveWindow<SignUpViewModel>
{
    public SignUpView()
    {
        InitializeComponent();
        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

Never keep a method named InitializeComponent in your code-behind view class if you are using the generator with AvaloniaNameGeneratorBehavior set to InitializeComponent (this is the default value). The private InitializeComponent method declared in your code-behind class hides the InitializeComponent method generated by Avalonia.NameGenerator, see Issue 69. If you wish to use your own InitializeComponent method (not the generated one), set AvaloniaNameGeneratorBehavior to OnlyProperties.

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
    Default value: InitializeComponent
    Determines if the generator should generate get-only properties, or the InitializeComponent method.

  • AvaloniaNameGeneratorDefaultFieldModifier
    Possible values: internal, public, private, protected
    Default value: internal
    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
    Default value: *
    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
    Default value: *
    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:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <AvaloniaNameGeneratorBehavior>InitializeComponent</AvaloniaNameGeneratorBehavior>
        <AvaloniaNameGeneratorDefaultFieldModifier>internal</AvaloniaNameGeneratorDefaultFieldModifier>
        <AvaloniaNameGeneratorFilterByPath>*</AvaloniaNameGeneratorFilterByPath>
        <AvaloniaNameGeneratorFilterByNamespace>*</AvaloniaNameGeneratorFilterByNamespace>
    </PropertyGroup>
    <!-- ... -->
</Project>

What do the generated sources look like?

For SignUpView, we get the following generated output when the source generator is in the InitializeComponent mode:

// <auto-generated />

using Avalonia.Controls;
using Avalonia.Markup.Xaml;

namespace Sample.App
{
    partial class SampleView
    {
        internal global::Avalonia.NameGenerator.Sandbox.Controls.CustomTextBox UserNameTextBox;
        public global::Avalonia.Controls.TextBlock UserNameValidation;
        private global::Avalonia.Controls.TextBox PasswordTextBox;
        internal global::Avalonia.Controls.TextBlock PasswordValidation;
        internal global::Avalonia.Controls.ListBox AwesomeListView;
        internal global::Avalonia.Controls.TextBox ConfirmPasswordTextBox;
        internal global::Avalonia.Controls.TextBlock ConfirmPasswordValidation;
        internal global::Avalonia.Controls.Button SignUpButton;
        internal global::Avalonia.Controls.TextBlock CompoundValidation;

        public void InitializeComponent(bool loadXaml = true, bool attachDevTools = true)
        {
            if (loadXaml)
            {
                AvaloniaXamlLoader.Load(this);
            }

// This will be added only if you install Avalonia.Diagnostics.
#if DEBUG
            if (attachDevTools)
            {
                this.AttachDevTools();
            } 
#endif

            UserNameTextBox = this.FindControl<global::Avalonia.NameGenerator.Sandbox.Controls.CustomTextBox>("UserNameTextBox");
            UserNameValidation = this.FindControl<global::Avalonia.Controls.TextBlock>("UserNameValidation");
            PasswordTextBox = this.FindControl<global::Avalonia.Controls.TextBox>("PasswordTextBox");
            PasswordValidation = this.FindControl<global::Avalonia.Controls.TextBlock>("PasswordValidation");
            AwesomeListView = this.FindControl<global::Avalonia.Controls.ListBox>("AwesomeListView");
            ConfirmPasswordTextBox = this.FindControl<global::Avalonia.Controls.TextBox>("ConfirmPasswordTextBox");
            ConfirmPasswordValidation = this.FindControl<global::Avalonia.Controls.TextBlock>("ConfirmPasswordValidation");
            SignUpButton = this.FindControl<global::Avalonia.Controls.Button>("SignUpButton");
            CompoundValidation = this.FindControl<global::Avalonia.Controls.TextBlock>("CompoundValidation");
        }
    }
}

If you enable the OnlyProperties source generator mode, you get:

// <auto-generated />

using Avalonia.Controls;

namespace Avalonia.NameGenerator.Sandbox.Views
{
    partial class SignUpView
    {
        internal global::Avalonia.NameGenerator.Sandbox.Controls.CustomTextBox UserNameTextBox => this.FindControl<global::Avalonia.NameGenerator.Sandbox.Controls.CustomTextBox>("UserNameTextBox");
        public global::Avalonia.Controls.TextBlock UserNameValidation => this.FindControl<global::Avalonia.Controls.TextBlock>("UserNameValidation");
        private global::Avalonia.Controls.TextBox PasswordTextBox => this.FindControl<global::Avalonia.Controls.TextBox>("PasswordTextBox");
        internal global::Avalonia.Controls.TextBlock PasswordValidation => this.FindControl<global::Avalonia.Controls.TextBlock>("PasswordValidation");
        internal global::Avalonia.Controls.TextBox ConfirmPasswordTextBox => this.FindControl<global::Avalonia.Controls.TextBox>("ConfirmPasswordTextBox");
        internal global::Avalonia.Controls.TextBlock ConfirmPasswordValidation => this.FindControl<global::Avalonia.Controls.TextBlock>("ConfirmPasswordValidation");
        internal global::Avalonia.Controls.Button SignUpButton => this.FindControl<global::Avalonia.Controls.Button>("SignUpButton");
        internal global::Avalonia.Controls.TextBlock CompoundValidation => this.FindControl<global::Avalonia.Controls.TextBlock>("CompoundValidation");
    }
}

avalonia.namegenerator's People

Contributors

dependabot[bot] avatar ngarside avatar robloo avatar romansoloweow avatar workgroupengineering avatar worldbeater avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.