CommunityToolkit.Maui v14.0.0
I am excited to debut two new source generators!
[BindableProperty][AttachedBindableProperty<T>]
These new source generators make it easier than ever to create a BindableProperty for your .NET MAUI apps by allowing us to write all the associated boiler-plate code for you. In fact, all Bindable Properties in CommunityToolkit.Maui are now automatically generated using these new source generators!
For an in-depth overview of both [BindableProperty] and [AttachedBindableProperty<T>], check out my comprehensive write-up:
👉 https://codetraveler.io/2026/01/29/introducing-bindable-property-source-generators/
Bug Fixes + New Features
Alongside the new Source Generators, this Release also brings important bug fixes and new features:
StatusBarBehavior- Fixes
StatusBarBehavioron Android 35+
- Fixes
Snackbar- Fixes a memory leak
Popup- Add extension method for
NavigatedFromEventArgs - Fixes tapping issues when using a
CollectionViewinPopup - Fixes a memory leak
- Add extension method for
Introducing Bindable Property Source Generators
Opt-into this Experimental Feature
We have decided to release this feature using the [Experimental] attribute. This allows us to let you try out its features and provide feedback while giving us the flexibility to update it with your feedback over the next few releases.
In the csproj file of your .NET MAUI app, add the following code:
<!-- Opt into Binbdable Property Source Generators -->
<PropertyGroup>
<NoWarn>MCTEXP001</NoWarn>
</PropertyGroup>In the mean-time, we will be writing more comprehensive documentation and writing Analyzers, similar to CommunityToolkit.MVVM, to help provide you the best coding experience!
Using [BindableProperty]
To leverage the Bindable Property Source Generator, first ensure you using a partial class. Then, add the partial keyword and attach the [BindableProperty] attribute to your property:
- Add the
partialkeyword to the class - Add the
partialkeyword the Property for which to generate an associated Bindable Property - Add the
[BindableProperty]attribute to the property to make it bindable
using CommunityToolkit.Maui;
namespace BindablePropertySourceGeneratorSample;
public partial class CustomButton : Button
{
[CommunityToolkit.Maui.BindableProperty]
public partial int? Number { get; set; }
}The above example generates the following Bindable Property:
public partial class CustomButton
{
/// <summary>
/// BindableProperty for the <see cref = "Number"/> property.
/// </summary>
public static readonly global::Microsoft.Maui.Controls.BindableProperty NumberProperty = global::Microsoft.Maui.Controls.BindableProperty.Create("Number", typeof(int?), typeof(BindablePropertySourceGeneratorSample.CustomButton), null, Microsoft.Maui.Controls.BindingMode.OneWay, null, null, null, null, null);
public partial int? Number { get => (int)GetValue(NumberProperty); set => SetValue(NumberProperty, value); }
}For more in-depth examples see my comprehensive write-up on [BindableProperty]:
👉 https://codetraveler.io/2026/01/29/introducing-bindable-property-source-generators/
Using [AttachedBindableProperty<T>]
Using [AttachedBindableProperty] is a bit different. This attribute is applied to either the Class or the Constructor, not a Property, as Attached Properties are not required to have an associated Property:
.NET Multi-platform App UI (.NET MAUI) attached properties enable an object to assign a value for a property that its own class doesn't define
To leverage the Attached Bindable Property Source Generator, first ensure you using a partial class. Then, add [AttachedBindableProperty<T>] attribute to either the class or constructor:
- Add the
partialkeyword to the class - Add the
[AttachedBindableProperty<T>]attribute to the class or constructor for which to generate an associated Attached Property
namespace BindablePropertySourceGeneratorSample;
[CommunityToolkit.Maui.AttachedBindableProperty<int>("Number")]
public partial class CustomButton : Button
{
public CustomButton()
{
}
}Alternatively, the attribute can be attached to the constructor:
namespace BindablePropertySourceGeneratorSample;
public partial class CustomButton : Button
{
[CommunityToolkit.Maui.AttachedBindableProperty<int>("Number")]
public CustomButton()
{
}
}Both examples above generate the following Attached Property along with its associated Get/Set methods:
public partial class CustomButton
{
/// <summary>
/// Attached BindableProperty for the Number property.
/// </summary>
public static readonly global::Microsoft.Maui.Controls.BindableProperty NumberProperty = global::Microsoft.Maui.Controls.BindableProperty.CreateAttached("Number", typeof(int), typeof(BindablePropertySourceGeneratorSample.CustomButton), null, (global::Microsoft.Maui.Controls.BindingMode)0, null, null, null, null, null);
/// <summary>
/// Gets Number for the <paramref name = "bindable"/> child element.
/// </summary>
public static int GetNumber(global::Microsoft.Maui.Controls.BindableObject bindable) => (int)bindable.GetValue(NumberProperty);
/// <summary>
/// Sets Number for the <paramref name = "bindable"/> child element.
/// </summary>
public static void SetNumber(global::Microsoft.Maui.Controls.BindableObject bindable, int value) => bindable.SetValue(NumberProperty, value);
}For more in-depth examples see my comprehensive write-up on [AttachedBindableProperty<T>]:
👉 https://codetraveler.io/2026/01/29/introducing-bindable-property-source-generators/
Breaking Changes
FileSaver
We heard your feedback! You now have more control over which Permissions you require and when you request them.
Developers must now manually request Permissions.StorageRead and Permissions.StorageWrite:
var readPermissionsRequest = await Permissions.RequestAsync<Permissions.StorageRead>();
var writePermissionsRequest = await Permissions.RequestAsync<Permissions.StorageWrite>();FolderPicker
We heard your feedback! You now have more control over which Permissions you require and when you request them.
Developers must now manually request Permissions.StorageRead and Permissions.StorageWrite:
var readPermissionsRequest = await Permissions.RequestAsync<Permissions.StorageRead>();
var writePermissionsRequest = await Permissions.RequestAsync<Permissions.StorageWrite>();SpeechToText
We heard your feedback! You now have more control over which Permissions you require and when you request them.
Developers must now manually request permissions for Permissions.Microphone and manually call ISpeechToText.RequestPermissions():
static async Task<bool> ArePermissionsGranted(ISpeechToText speechToText, CancellationToken token = default)
{
var microphonePermissionStatus = await Permissions.RequestAsync<Permissions.Microphone>();
var isSpeechToTextRequestPermissionsGranted = await speechToText.RequestPermissions(token);
return microphonePermissionStatus is PermissionStatus.Granted
&& isSpeechToTextRequestPermissionsGranted;
}What's Changed
- Fix StatusBar on Android 35+ by @TheCodeTraveler in #2939
- Fixes Obsolete Warnings and NuGet Package Dependency Warnings by @VladislavAntonyuk in #2944
- Update ColorConversionExtensions.shared.cs by @stephenquan in #2945
- Add popup related navigation extension methods by @jamesbrooksbank in #2955
- [Housekeeping] Add
ReferenceAssembliesExtensionsextension forReferenceAssemblies.Net.Net100by @TheCodeTraveler in #2956 - Update
[BindableProperty]Support for Additional Scenarios, AddCommunityToolkit.Maui.SourceGenerators.Internal.UnitTests, Implement[BindableProperty]for Behaviors by @TheCodeTraveler in #2932 - Add
CommunityToolkit.Maui.SourceGenerator.Benchmarks, Reduce Memory Allocations on[BindableProperty]Source Generator by @TheCodeTraveler in #2960 - Use
[BindableProperty]for RatingView by @CliffAgius in #2964 - Cleanup Popup Resources When Closed by @AlejoTorresLeon in #2971
- Add
[Experimental]To[BindableProperty]by @TheCodeTraveler in #2990 - Extend BindableProperty source gen to handle partial property initializers by @stephenquan in #2987
- Add BoxView behind the Popup content to safely handle touch interaction by @bijington in #2997
- Bindable property for Popup by @ne0rrmatrix in #2991
- Remove
BindablePropertyAttribute.DefaultValueby @TheCodeTraveler in #2995 - Refactor
Animationsto use [BindableProperty] partial properties by @ne0rrmatrix in #3013 - Refactor Views to use
[BindableProperties]partial properties by @ne0rrmatrix in #3017 - Implement
[BindableProperty]for Converters by @TheCodeTraveler in #3018 - Implement
[BindableProperty]forImageSources, Add[BindableProperty]Support forinternalProperties by @TheCodeTraveler in #3019 - Use
Copyinstead ofMovein FileSaver UI on iOS by @matt-goldman in #2981 - Support null values in NumericValidationBehavior by @reck1610 in #2886
- Refactor Layouts to use [BindableProperty] partial properties by @ne0rrmatrix in #3016
- Implement
[BindableProperty]for ValidationBehaviors by @TheCodeTraveler in #3000 - Remove
ReferenceAssembliesExtensionsby @TheCodeTraveler in #3038 - Create
[AttachedBindableProperty<T>]by @TheCodeTraveler in #3024 - Fix memory leak on snackbar by @pictos in #3034
- Fix Windows Picker Initial Path is not set by @VladislavAntonyuk in #3030
- Fix clicking on notification does not restore activity by @ne0rrmatrix in #2979
- Prepare
[AttachedBindableProperty<T>]and[BindableProperty]for Release by @TheCodeTraveler in #3047 - Fix memory leak by changing now playing artwork request handler by @MarcelStommel in #3051
New Contributors
- @jamesbrooksbank made their first contribution in #2955
- @AlejoTorresLeon made their first contribution in #2971
- @matt-goldman made their first contribution in #2981
- @reck1610 made their first contribution in #2886
- @MarcelStommel made their first contribution in #3051
Full Changelog: 13.0.0...14.0.0