boilerplatezero 1.0.2

There is a newer version of this package available.
See the version list below for details.
dotnet add package boilerplatezero --version 1.0.2                
NuGet\Install-Package boilerplatezero -Version 1.0.2                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="boilerplatezero" Version="1.0.2">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add boilerplatezero --version 1.0.2                
#r "nuget: boilerplatezero, 1.0.2"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install boilerplatezero as a Cake Addin
#addin nuget:?package=boilerplatezero&version=1.0.2

// Install boilerplatezero as a Cake Tool
#tool nuget:?package=boilerplatezero&version=1.0.2                

boilerplatezero

boilerplatezero (BPZ) is a collection of C# source generators that simplifies the code that needs to be written for common C# patterns.


WPF Dependency Property Generator

Dependency properties in WPF are great! However, they do require quite a bit of ceremony in order to define one. Luckily, dependency properties (and attached properties) always follow the same pattern when implemented. As such, this kind of boilerplate code is the perfect candidate for a source generator.

The dependency property generator in BPZ works by identifying DependencyProperty and DependencyPropertyKey fields that are initialized with calls to appropriately-name Gen or GenAttached methods. When this happens, the source generator adds private static classes as nested types inside your class & implements the dependency property for you.

🛠 Example Dependency Property

// Dependency property written idiomatically:
private static readonly DependencyPropertyKey FooPropertyKey = DependencyProperty.RegisterReadOnly(nameof(Foo), typeof(string), typeof(MyClass), null);
public static readonly DependencyProperty FooProperty = FooPropertyKey.DependencyProperty;
public string Foo
{
    get => (string)this.GetValue(FooProperty);
    private set => this.SetValue(FooPropertyKey, value);
}

// Dependency property written with BPZ:
private static readonly DependencyPropertyKey FooPropertyKey = Gen.Foo<string>();

🛠 Example Attached Property

// Attached property written idiomatically:
private static readonly DependencyPropertyKey BarPropertyKey = DependencyProperty.RegisterAttachedReadOnly("Bar"), typeof(string), typeof(MyClass), null);
public static readonly DependencyProperty BarProperty = BarPropertyKey.DependencyProperty;
public static string GetBar(DependencyObject d) => (string)d.GetValue(BarProperty);
private static void SetBar(DependencyObject d, string value) => d.SetValue(BarPropertyKey, value);

// Attached property written with BPZ:
private static readonly DependencyPropertyKey BarPropertyKey = GenAttached.Bar<string>();

🛠 Generated Code

Here's an example of 👩‍💻 hand-written code & the corresponding 🤖 generated code. Note that the default value for the dependency property is specified in the user's code & the documentation comment on IdPropertyKey is copied to the generated Id property.

// 👩‍💻 Widget.cs
namespace Goodies
{
    public partial class Widget : DependencyObject
    {
        /// <Summary>Gets the ID of this instance.</Summary>
        protected static readonly DependencyPropertyKey IdPropertyKey = Gen.Id("<unset>");
    }
}

// 🤖 Widget.g.cs (actual name may vary)
namespace Goodies
{
    partial class Widget
    {
        public static readonly DependencyProperty IdProperty = IdPropertyKey.DependencyProperty;

        /// <Summary>Gets the ID of this instance.</Summary>
        public string Id
        {
            get => (string)this.GetValue(IdProperty);
            protected set => this.SetValue(IdPropertyKey, value);
        }

        private static partial class Gen
        {
            public static DependencyPropertyKey Id<T>(T defaultValue)
            {
                PropertyMetadata metadata = new PropertyMetadata(defaultValue);
                return DependencyProperty.RegisterReadOnly("Id", typeof(T), typeof(Widget), metadata);
            }
        }
    }
}

✨ Features

  • generates instance properties for dependency properties
  • generates static methods for attached properties
  • optional default values
  • supports nullable types
    public static readonly DependencyProperty IsCheckedProperty = Gen.IsChecked<bool?>(false);
    public static readonly DependencyProperty NameProperty = Gen.Name<string?>();
    
  • access modifiers are preserved on generated members
  • documentation is preserved (for dependency properties) on generated members
  • generates dependency property fields for read-only properties (if necessary)
    // 👩‍💻 user
    // Instance field `FooProperty` is defined, so it will not be generated.
    // Access modifiers for generated get/set of the `Foo` instance property will match the property & key.
    private static readonly DependencyPropertyKey FooPropertyKey = GenAttached.Foo(3.14f);
    protected static readonly DependencyProperty FooProperty = FooPropertyKey.DependencyProperty;
    
    // Instance field `BarProperty` is not defined, so it will be generated.
    private static readonly DependencyPropertyKey BarPropertyKey = Gen.Bar<Guid>();
    
    // 🤖 generated
    protected float Foo
    {
        get => (float)this.GetValue(FooProperty);
        private set => this.SetValue(FooPropertyKey, value);
    }
    
    public static readonly DependencyProperty BarProperty = BarPropertyKey.DependencyProperty;
    public System.Guid Bar
    {
        get => (System.Guid)this.GetValue(BarProperty);
        private set => this.SetValue(BarPropertyKey, value);
    }
    
  • attached properties may constrain their target type by specifying a generic type parameter on GenAttached
    // 👩‍💻 user
    // Attached property `Standard` may be used with any dependency object.
    public static readonly DependencyProperty StandardProperty = GenAttached.Standard("🍕");
    
    // Attached property `IsFancy` may only be used with objects of type <see cref="Widget"/>.
    public static readonly DependencyProperty IsFancyProperty = GenAttached<Goodies.Widget>.IsFancy(true);
    
    // 🤖 generated
    public static string GetStandard(DependencyObject d) => (string)d.GetValue(StandardProperty);
    public static void SetStandard(DependencyObject d, string value) => d.SetValue(StandardProperty, value);
    
    public static bool GetIsFancy(Goodies.Widget d) => (bool)d.GetValue(IsFancyProperty);
    public static void SetIsFancy(Goodies.Widget d, bool value) => d.SetValue(IsFancyProperty, value);
    
There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.0.0 583 2/6/2023
2.0.0-beta 404 2/6/2023
1.8.0 13,036 6/6/2022
1.7.2 838 5/23/2022
1.7.1 1,341 10/16/2021
1.7.0 436 7/21/2021
1.6.0 413 7/6/2021
1.5.2 450 7/3/2021
1.5.1 378 6/26/2021
1.5.0 394 6/13/2021
1.4.1 531 1/2/2021
1.4.0 431 12/29/2020
1.3.0 361 12/29/2020
1.2.0 460 12/4/2020
1.1.0 487 11/29/2020
1.0.2 443 11/28/2020
1.0.1 495 11/26/2020
1.0.0 425 11/26/2020