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.
.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 Behavior
s inside of DataTemplates (eg inside of CollectionView, ListView etc.) are both fundamentally broken.
The .NET MAUI engineers made the decision that Behavior
s do not automatically inherit their parents' BindingContext
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 Behavior
s.
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, 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>
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));