Search code examples
c#mauimaui-community-toolkitmaui-markup-community-toolkit

How to use complex / nested bindings with TypedBinding in .NET MAUI C# Markup?


I'm using TypedBindings in CommunityToolkit.Maui.Markup and my binding is not working as expected when binding to a property nested inside of another property.

In the sample code below, the Label text is updated using the "old" binding method that uses Reflection:

.Bind(Label.TextProperty, path: "NestedObject.Test")

but the Label text does not get updated when using TypedBindings (no reflection):

.Bind(Label.TextProperty, 
         static (TestModel myModel) => myModel.NestedObject.Test)

Code

class TestView : ContentPage
{
    TestModel model;

    public TestView()
    {
        model = new TestModel();
        BindingContext = model;

        Content = new Grid
        {
            Children =
            {
                new VerticalStackLayout
                {
                    new Label
                    {

                    }.Bind(Label.TextProperty, path: "NestedObject.Test"),

                    new Label
                    {

                    }.Bind(Label.TextProperty, 
                            static (TestModel myModel) => myModel.NestedObject.Test,

                    new Entry
                    {

                    }.Bind(Entry.TextProperty, 
                            static (TestModel model) => model.NestedObject.Test
                            static (TestModel model, string value) => model.NestedObject.Test = value),

                }
            }
        };
    }
}

partial class TestModel : ObservableObject
{
    [ObservableProperty]
    NestedObject nestedObject = new();
    [ObservableProperty]
    NestedObject? nestedObject2;
    [ObservableProperty]
    string title = "My Title";
}

partial class NestedObject : ObservableObject
{
    [ObservableProperty]
    string test = "Initial";
}

Solution

  • For TypedBindings, a nested binding requires you to include the handlers parameter.

    It looks like you're just missing the handlers parameter. Below is the updated code as well as a GIF of the working sample app.

    I've also submitted a PR here adding the handlers to demonstrate the missing code: https://github.com/Falco94/CommunityToolkit.IssueTest/pull/1

    Updated Sample Code

    public class TestView : ContentPage
    {
        TestModel model;
    
        public TestView()
        {
            model = new TestModel();
            BindingContext = model;
    
            Content = new Grid
            {
                Children =
                {
                    new VerticalStackLayout
                    {
                        new Label
                        {
    
                        }.Bind(Label.TextProperty, path: "NestedObject.Test"),
    
                        new Label
                        {
    
                        }.Bind(Label.TextProperty, 
                                getter: static (TestModel myModel) => myModel.NestedObject.Test,
                                handlers: new (Func<TestModel, object?>, string)[]
                                {
                                    (vm => vm, nameof(TestModel.NestedObject)),
                                    (vm => vm.NestedObject, nameof(TestModel.NestedObject.Test)),
                                }),
    
                        new Entry
                        {
    
                        }.Bind(Entry.TextProperty, 
                                getter: static (TestModel model) => model.NestedObject.Test, 
                                handlers: new (Func<TestModel, object?>, string)[]
                                {
                                    (vm => vm, nameof(TestModel.NestedObject)),
                                    (vm => vm.NestedObject, nameof(TestModel.NestedObject.Test)),
                                },
                                setter: (TestModel model, string value) => model.NestedObject.Test = value),
    
                    }
                }
            };
        }
    }
    

    Working Sample

    Simulator Screen Recording - iPhone 15 - 2023-11-29 at 12 00 37

    Nested Binding Examples in CommunityToolkit.Maui.Markup.UnitTests

    https://github.com/CommunityToolkit/Maui.Markup/blob/08459a7e128de0e764f4e293cc191bfa293b79bd/src/CommunityToolkit.Maui.Markup.UnitTests/TypedBindingExtensionsTests.cs#L308-L461