.netxamlmauimaui-community-toolkit

Behavior Binding Not Working in CommunityToolkit.Maui


I have updated to use .NET 9 and subsequently updated CommunityToolkit.Maui to v10.0 because it is the latest version supporting .NET MAUI, but it seems to have broken the Behavior in my app.

Specifically, I am using the CommunityToolkit.Maui.Behaviors.IconTintColorBehavior on an Image, binding its TintColor to a property in my ViewModel (see code below).

<Image Source="shield.png">
    <Image.Behaviors>
        <mct:IconTintColorBehavior TintColor="{Binding ImageTintColor}" />
    </Image.Behaviors>
</Image>

In earlier versions of CommunityToolkit.Maui this code worked fine, but for some reason my binding is no longer firing.


Solution

  • .NET MAUI Community Toolkit Maintainer here.

    Yes, this is a breaking change in CommunityToolkit.Maui v10.

    tl;dr We should've never automatically assigned your Behavior's BindingContext, and we have now removed that logic.

    I acknowledge that this is a painful breaking change. And I also acknowledge that we messed up by previously assigning the BindingContext for you automatically. It raised many issues over the years for which we spent many hours implementing workarounds, but it ultimately lead us to creating workarounds for workaround to meet each user's unique use-case. Two glaring bugs that we were never able to fix is re-using a Behavior multiple times, and using our Behaviors inside of DataTemplates (eg inside of CollectionView, ListView etc.) are both fundamentally broken.

    Background

    The .NET MAUI engineers made the decision that Behaviors do not automatically inherit their parents' BindingContext

    enter image description here

    This was a breaking change from the Xamarin.CommunityToolkit, the library that I ported to .NET MAUI to create CommunityToolkit.Maui.

    Instead of following .NET MAUI's lead and requiring developers to set their own BindingContext for each Behavior, we decided to help by doing it automatically for you. However, in our effort to help make developers' lives easier, we resulted in creating more issues, causing painful bugs for developers.

    After spending many hours trying to deduce a solution, the only solution we found was to revert our original implementation and to stop automatically assigning the BindingContext for each of our Behaviors.

    Solution

    The fix is easy - we just need to ensure you assign a BindingContext for a Behavior that is using a Binding. The best way that I recommend to do this is to bind Behavior.BindingContext to the BindingContext of the control it is attached to:

    In XAML

    In XAML, we can use x:Name to name the control to which we are attaching our Binding, and then create a Binding to its BindingContext:

    <Image
        x:Name="TintedImage"
        Source="shield.png">
        <Image.Behaviors>
            <mct:IconTintColorBehavior 
                BindingContext="{Binding Path=BindingContext, Source={x:Reference: TintedImage}}"
                TintColor="{Binding ImageTintColor}" />
        </Image.Behaviors>
    </Image>
    

    In C# using CommunityTooklit.Maui.Markup

    In C# using CommunityTooklit.Maui.Markup, we can use .Assign<T>(out T) to create a reference to the control to which we are attaching our Binding, and then create a Binding to its BindingContext:

    new Image()
        .Source("shield.png")
        .Assign(out Image tintedImage)
        .Behaviors(new IconTintColorBehavior()
                    .Bind(IconTintColorBehavior.BindingContext, 
                            getter: static image => image.BindingContext,
                            source: tintedImage)
                    .Bind(IconTintColorBehavior.TintColorProperty
                            getter: static (MyViewModel vm) => vm.ImageTintColor));