BindableObject extensions

The BindableObject extensions provide a series of extension methods that support configuring Bindings on a BindableObject.

The extensions offer the following methods:

Bind

The Bind method offers a number of overloads providing different convenience around the setup of a Binding. For further information of the possibilities of Binding data in a .NET MAUI application refer to the Microsoft documentation.

Example

There are a number of overloads for the Bind method.

One way binding

A one way binding from a view model (RegistrationViewModel) property called RegistrationCode to the Text property of an Label can be created as follows:

new Entry()
    .Bind(Label.TextProperty, 
            getter: static (RegistrationViewModel vm) => vm.RegistrationCode)

Two way binding

A two way binding from a view model (RegistrationViewModel) property called RegistrationCode to the Text property of an Entry can be created as follows:

new Entry()
    .Bind(Entry.TextProperty,
            getter: static (RegistrationViewModel vm) => vm.RegistrationCode,
            setter: static (RegistrationViewModel vm, string code) => vm.RegistrationCode = code)

Complex (Nested) Bindings

When binding to a property inside of a property (also known as "Nested Bindings"), the handlers parameter is required. The handler parameter requires a reference to each Property in the complex binding chain.

Along with the example below, you can find additonal examples of complex bindings in the Unit Tests for CommunityToolkit.Maui.Markup.

Complex (Nested) Bindings Example

Using the below ViewModel class, we can create a nested two-way binding directly to ViewModel.NestedObject.Text using the handlers parameter:

new Entry().Bind(
    Entry.TextProperty,
    getter: static (ViewModel vm) => vm.NestedObject.Text,
    handlers: new (Func<ViewModel, object?>, string)[]
             {
                (vm => vm, nameof(ViewModel.NestedObject)),
                (vm => vm.NestedObject, nameof(ViewModel.NestedObject.Text)),
             },
    setter: static (ViewModel vm, string text) => vm.NestedObject.Text = text);
class ViewModel
{
    public NestedObject NestedObject { get; set; } = new();

    public required string Text { get; set; }
}

class NestedObject
{
    public required string Text { get; set; }
}

Default property

The Bind method can be called without specifying the property to set the binding up for, this will utilize the defaults provided by the library with the full list at the GitHub repository.

The default property to bind for an Entry is the text property. So the above example could be written as:

new Entry().Bind(nameof(ViewModel.RegistrationCode))

Warning

This approach will result in some level of Reflection being used and will not perform as well as the Explicit property approach.

Value conversion

The Bind method allows for a developer to supply the Converter that they wish to use in the binding or simply provide a mechanism to use an inline conversion.

Converter
new Entry()
    .Bind(Entry.TextProperty,
            getter: static (RegistrationViewModel vm) => vm.RegistrationCode,
            converter: new TextCaseConverter { Type = TextCaseType.Upper });

See TextCaseConverter for the documentation on it's full usage.

Inline conversion
new Entry()
    .Bind(Entry.TextProperty,
            getter: static (RegistrationViewModel vm) => vm.RegistrationCode,
            convert: (string? text) => text?.ToUpperInvariant());

Multiple Bindings

Multiple Bindings can be aggregated together leveraging the IMultiValueConverter.

The convert parameter is a Func that is required to convert the multiple bindings to the required result.

new Label()
    .Bind(Label.TextProperty,
            binding1: new Binding(nameof(ViewModel.IsBusy)),
            binding2: new Binding(nameof(ViewModel.LabelText)),
            convert: ((bool IsBusy, string LabelText) values) => values.IsBusy ? string.Empty : values.LabelText)

BindCommand

The BindCommand method provides a helpful way of configuring a binding to a default provided by the library with the full list at the GitHub repository.

The default command to bind for an Button is the Command property. So the following example sets up a binding to that property.

new Button().BindCommand(static (ViewModel vm) => vm.SubmitCommand);

The above could also be written as:

Note

If the default command does not result in binding to your desired command then you can use the Bind method.

new Button()
    .Bind(Entry.CommandProperty,
            getter: static (RegistrationViewModel vm) => vm.SubmitCommand,
            mode: BindingMode.OneTime);

Gesture Binding

Gesture bindings allow us to create an ClickGestureRecognizer, SwipeGestureRecognizer, TapGestureRecognizer, attach it to any element that implements IGestureRecognizer and bind it to an ICommand in our ViewModel.

BindClickGesture

The following example demonstrates how to create a ClickGestureRecognizer that requires 2 clicks to activate, attach it to a Label and bind it to an ICommand property called ClickCommand in our ViewModel:

new Label()
    .BindClickGesture(
        static (ViewModel vm) => vm.ClickCommand,
        commandBindingMode: BindingMode.OneTime,
        numberOfClicksRequired: 2));

BindSwipeGesture

The following example demonstrates how to create a SwipeGestureRecognizer that requires SwipeDirection.Up for its SwipeDirection and a minumum 200-point distance for its Threshold, then attach it to a Label and bind it to an ICommand property called SwipeCommand in our ViewModel:

new Label()
    .BindSwipeGesture(
        static (ViewModel vm) => vm.SwipeCommand,
        commandBindingMode: BindingMode.OneTime,
        direction: SwipeDirection.Up,
        threshold: 200);

BindTapGesture

The following example demonstrates how to create a ClickGestureRecognizer that requires 2 taps to activate, attach it to a Label and bind it to an ICommand property called TapCommand in our ViewModel:

new Label()
    .BindTapGesture(
        static (ViewModel vm) => vm.TapCommand,
        commandBindingMode: BindingMode.OneTime,
        numberOfTapsRequired: 2));

AppThemeBinding

The AppThemeBinding method allows for a light and dark value to assigned to a BindableProperty so that when the applications AppTheme is modified the appropriate value will be used for that theme.

The following example will assign the color black to the Text property of the Label control if the application is running in light theme and white in dark theme.

new Label().AppThemeBinding(Label.TextColorProperty, Colors.Black, Colors.White);

Note

There is a more specific method when dealing with Color properties. AppThemeColorBinding will perform the same underlying behavior as AppThemeBinding but it requires a set of Color parameters.

For more information refer to the Theming documentation.

Examples

You can find an example of these extension methods in action throughout the .NET MAUI Community Toolkit Sample Application.

API

You can find the source code for the BindableObject extension methods over on the .NET MAUI Community Toolkit GitHub repository.