Skip to content

[Proposal] Add a new public API to allow defining TypedBinding in code #19912

@simonrozsival

Description

@simonrozsival

Description

MAUI currently has two general purpose binding classes: Binding and TypedBinding<TSource, TProperty>. The TypedBinding class isn't public and it can only be used through XAML code compiled using XamlC or through the .NET MAUI Markup Community Toolkit.

I'm proposing a new API which will allow developers to define type-safe bindings directly. There are several nice properties of the new API:

  • unlike the string-based paths, the expression-based bindings are trimming-friendly (it would contribute towards [iOS] Resolving Trimming Warnings for dotnet new maui #19397)
  • IDE IntelliSense shows suggestions when defining the binding
  • the performance seems to be on par with manually defined TypedBinding (*)
  • we can assemble the array of handlers for the TypedBinding constructor and customers don't need to define it manually which would be the case if we just made the class public

(*): Based on running the SpeedTestApply and SpeedTestSetBC unit tests in a PoC implementation (net9.0...simonrozsival:maui:typed-binding-from-expression). The PoC also shows that adding System.Linq.Expressions to the dotnet new maui app adds 89,862 B to the final .ipa (1.25 %)

Public API Changes

public static partial class BindableObjectExtensions
{
    public static void SetBinding<TSource, TProperty>(
        this BindableObject self,
        BindableProperty property,
        Expression<Func<TSource, TProperty>> getter,
        Action<TSource, TProperty>? setter = null,
	BindingMode mode = BindingMode.Default,
	IValueConverter? converter = null,
	object? converterParameter = null,
	string? stringFormat = null,
	object? source = null,
	string? updateSourceEventName = null,
	object? fallbackValue = null,
	object? targetNullValue = null)
    {
        // ...
    }
}

Intended Use-Case

Currently:

bindableObject.SetBinding(SomeProperty, new Binding("Simple.Path");
bindableObject.SetBinding(SomeProperty, new Binding("Path.To.Property[1]");
bindableObject.SetBinding(SomeProperty, "Path.To.Property[1]");

Using the new API:

bindableObject.SetBinding(SomeProperty, static (SomeType source) => source.Simple.Path);

// for paths with custom indexers, it is not possible to generate the setter from the expression,
// so an explicit setter is required:
bindableObject.SetBinding(
    SomeProperty,
    getter: static (SomeType x) => x.Path.To.Property[1],
    setter: static (x, value) => x.Path.To.Property[1] = value);

Notes

Typed bindings still don't support relative binding sources. I suspect this is one of the reasons why the TypedBinding type hasn't been made available to public yet and why it's only used by XamlC where it is applicable.

/cc @StephaneDelcroix

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions