Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
simonrozsival opened this issue Jan 15, 2024 · 1 comment
Closed
Assignees
Labels

Comments

@simonrozsival
Copy link
Member

simonrozsival commented Jan 15, 2024

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

@simonrozsival
Copy link
Member Author

We've implemented this in #21725 and it was merged into the net9.0 branch

@github-actions github-actions bot locked and limited conversation to collaborators Jul 6, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants