BindableProps 1.1.0-beta

This is a prerelease version of BindableProps.
There is a newer version of this package available.
See the version list below for details.
dotnet add package BindableProps --version 1.1.0-beta                
NuGet\Install-Package BindableProps -Version 1.1.0-beta                
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="BindableProps" Version="1.1.0-beta" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add BindableProps --version 1.1.0-beta                
#r "nuget: BindableProps, 1.1.0-beta"                
#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 BindableProps as a Cake Addin
#addin nuget:?package=BindableProps&version=1.1.0-beta&prerelease

// Install BindableProps as a Cake Tool
#tool nuget:?package=BindableProps&version=1.1.0-beta&prerelease                

BindableProps

NuGet Build Status

I spend hours to save your moments.

This library helps you to reduce writing boilerplate code when creating your custom UI components.

Example Usage

Let say you want to create your own text input. Here's how it looks:

namespace MyMauiApp.Controls;

public class TextInput : ContentView
{
    public string Text
    {
        get => (string)GetValue(TextInput.TextProperty);
        set => SetValue(TextInput.TextProperty, value);
    }

    public static readonly BindableProperty TextProperty = BindableProperty.Create(
        nameof(Text), typeof(string), typeof(TextInput), string.Empty
        );

    public string PlaceHolder
    {
        get => (string)GetValue(TextInput.PlaceHolderProperty);
        set => SetValue(TextInput.PlaceHolderProperty, value);
    }

    public static readonly BindableProperty PlaceHolderProperty = BindableProperty.Create(
        nameof(PlaceHolder), typeof(string), typeof(TextInput), string.Empty
        );


    public TextInput()
    {
        // Implement your logic
    }
}

With BindableProps, your code will become like this:

using BindableProps;

namespace MyMauiApp.Controls;

// Notice: Your class must be partial class
public partial class TextInput : ContentView
{
    [BindableProp]
    string text;

    [BindableProp]
    string placeHolder;


    public TextInput()
    {
        // This piece is same as above
    }
}

The real magic happens at Solution Explorer > Dependencies > Analyzers > BindablePropsSG

image-20220704231041505

What you would see in TextInput.g.cs is the boilerplate code which you had to write. I'll write them for you!

using BindableProps;

namespace MyMauiApp.Controls
{
    public partial class TextInput
    {

        public static readonly BindableProperty TextProperty = BindableProperty.Create(
            nameof(Text),
            typeof(string),
            typeof(TextInput),
            default,
            BindingMode.Default,
            null,
            null,
            null,
            null,
            null
        );

        public string Text
        {
            get => text;
            set 
            { 
                text = value;
                SetValue(TextInput.TextProperty, text);
            }
        }

        public static readonly BindableProperty PlaceHolderProperty = BindableProperty.Create(
            nameof(PlaceHolder),
            typeof(string),
            typeof(TextInput),
            default,
            BindingMode.Default,
            null,
            null,
            null,
            null,
            null
        );

        public string PlaceHolder
        {
            get => placeHolder;
            set 
            { 
                placeHolder = value;
                SetValue(TextInput.PlaceHolderProperty, placeHolder);
            }
        }

    }
}

The above example is the minimal amount of code to work. Here is the complete features:

public partial class TextInput : ContentView
{
    // Create prop with a few settings
    [BindableProp(DefaultBindingMode = ((int)BindingMode.TwoWay))]
    string text = "From every time";

    // Full setting
    [BindableProp(
        DefaultBindingMode = ((int)BindingMode.OneWay),
        ValidateValueDelegate = nameof(ValidateValue),
        PropertyChangedDelegate = nameof(PropertyChangedDelegate),
        PropertyChangingDelegate = nameof(PropertyChangingDelegate),
        CoerceValueDelegate = nameof(CoerceValueDelegate),
        CreateDefaultValueDelegate = nameof(CreateDefaultValueDelegate)
        )]
    string placeHolder = "Always!";

    static bool ValidateValue(BindableObject bindable, object value)
    {
        return true;
    }

    static void PropertyChangedDelegate(BindableObject bindable, object oldValue, object newValue)
    {
        // Do something
    }

    static void PropertyChangingDelegate(BindableObject bindable, object oldValue, object newValue)
    {
        // Do something
    }

    static object CoerceValueDelegate(BindableObject bindable, object value)
    {
        // Do something
        return 0;
    }

    static object CreateDefaultValueDelegate(BindableObject bindable)
    {
        // Do something
        return string.Empty;
    }
}

And the corresponding result would like:

public partial class TextInput
    {
        public static readonly BindableProperty TextProperty = BindableProperty.Create(
            nameof(Text),
            typeof(string),
            typeof(TextInput),
            "From every time",
            ((int)BindingMode.TwoWay),
            null,
            null,
            null,
            null,
            null
        );

        public string Text
        {
            get => text;
            set 
            { 
                text = value;
                SetValue(TextInput.TextProperty, text);
            }
        }

        public static readonly BindableProperty PlaceHolderProperty = BindableProperty.Create(
            nameof(PlaceHolder),
            typeof(string),
            typeof(TextInput),
            "Always!",
            ((int)BindingMode.OneWay),
            ValidateValue,
            PropertyChangedDelegate,
            PropertyChangingDelegate,
            CoerceValueDelegate,
            CreateDefaultValueDelegate
        );

        public string PlaceHolder
        {
            get => placeHolder;
            set 
            { 
                placeHolder = value;
                SetValue(TextInput.PlaceHolderProperty, placeHolder);
            }
        }

    }

Finally, you can use your component in other page/view like a normal component. For example, at MainPage.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:vm="clr-namespace:MyMauiApp.ViewModels"
             xmlns:controls="clr-namespace:MyMauiApp.Controls"
             x:Class="MyMauiApp.MainPage"
             x:DataType="vm:MainPageViewModel">
    
    <controls:TextInput PlaceHolder="Say you do"
                        Text="{Binding MyLoveStory, Mode=TwoWay}" />
</ContentPage>

Roadmap

The BindableProp along is just not enough for covering all use-cases of BindableProperty. Planning features:

Attribute Equivalent/Description
BindableAttachedProp BindableProperty.CreateAttached
BindableAttachedReadOnlyProp BindablePropertyKey.CreateAttachedReadOnly
BindableReadOnlyProp BindablePropertyKey.CreateReadOnly
AllBindableProps Put this to your class,<br />Default BindableProp to all field members
IgnoredProp AllBindableProps should ignore this field
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-android31.0 is compatible.  net6.0-ios was computed.  net6.0-ios15.4 is compatible.  net6.0-maccatalyst was computed.  net6.0-maccatalyst15.4 is compatible.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net6.0-windows10.0.19041 is compatible.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
1.4.3 286 5/13/2024
1.4.2 89 5/13/2024
1.4.1 86 5/11/2024
1.4.0 136 5/4/2024
1.3.10 275 2/12/2024
1.3.9 377 8/19/2023
1.3.8 230 6/24/2023
1.3.7 286 4/17/2023
1.3.6 181 4/16/2023
1.3.5 186 4/11/2023
1.3.5-beta 133 4/11/2023
1.3.4 336 1/8/2023
1.3.3 305 1/8/2023
1.3.2 299 1/7/2023
1.3.1 296 1/7/2023
1.3.0 305 1/6/2023
1.2.1 300 1/5/2023
1.2.0 461 7/10/2022
1.2.0-beta 159 7/10/2022
1.1.9 434 7/10/2022
1.1.8 431 7/10/2022
1.1.8-beta 180 7/9/2022
1.1.7-beta 164 7/8/2022
1.1.3-beta 156 7/8/2022
1.1.2-beta 156 7/8/2022
1.1.1-beta 167 7/8/2022
1.1.0-beta 164 7/7/2022
1.0.7-beta 177 7/5/2022
1.0.6-beta 145 7/4/2022
1.0.4-beta 160 7/3/2022
1.0.3-beta 165 7/3/2022
1.0.2-beta 169 7/3/2022
1.0.1-beta 173 7/1/2022
1.0.0-beta 163 7/1/2022