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

Compiled bindings updates #2556

Merged
merged 15 commits into from
Oct 8, 2024
127 changes: 115 additions & 12 deletions docs/fundamentals/data-binding/compiled-bindings.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Compiled bindings"
description: "Compiled bindings can be used to improve data binding performance in .NET MAUI applications."
ms.date: 09/27/2024
ms.date: 10/08/2024
---

# Compiled bindings
Expand All @@ -24,12 +24,12 @@ Compiled bindings improve data binding performance in .NET MAUI applications by

## Compiled bindings in XAML

To use compiled bindings in XAML, set an `x:DataType` attribute on a <xref:Microsoft.Maui.Controls.VisualElement> to the type of the object that the <xref:Microsoft.Maui.Controls.VisualElement> and its children will bind to. It's recommended to set the `x:DataType` attribute at the same level in the view hierarchy as the `BindingContext` is set. However, this attribute can be re-defined at any location in a view hierarchy.
To use compiled bindings in XAML, set an `x:DataType` attribute on a <xref:Microsoft.Maui.Controls.VisualElement> to the type of the object that the <xref:Microsoft.Maui.Controls.VisualElement> and its children will bind to. It's recommended to set the `x:DataType` attribute at the same level in the view hierarchy as the <xref:Microsoft.Maui.Controls.BindableObject.BindingContext> is set. However, this attribute can be re-defined at any location in a view hierarchy.

> [!NOTE]
> [!IMPORTANT]
> Compiled bindings require the use of XAML compilation, which is enabled by default in .NET MAUI. If you've disabled XAML compilation, you'll need to enable it. For more information, see [XAML Compilation](~/xaml/xamlc.md).

To use compiled bindings in XAML, the `x:DataType` attribute must be set to a string literal, or a type using the `x:Type` markup extension. At XAML compile time, any invalid binding expressions will be reported as build errors. However, the XAML compiler will only report a build error for the first invalid binding expression that it encounters. Any valid binding expressions that are defined on the <xref:Microsoft.Maui.Controls.VisualElement> or its children will be compiled, regardless of whether the `BindingContext` is set in XAML or code. Compiling a binding expression generates compiled code that will get a value from a property on the *source*, and set it on the property on the *target* that's specified in the markup. In addition, depending on the binding expression, the generated code may observe changes in the value of the *source* property and refresh the *target* property, and may push changes from the *target* back to the *source*.
To use compiled bindings in XAML, the `x:DataType` attribute must be set to a string literal, or a type using the `x:Type` markup extension. At XAML compile time, any invalid binding expressions will be reported as build errors. However, the XAML compiler will only report a build error for the first invalid binding expression that it encounters. Any valid binding expressions that are defined on the <xref:Microsoft.Maui.Controls.VisualElement> or its children will be compiled, regardless of whether the <xref:Microsoft.Maui.Controls.BindableObject.BindingContext> is set in XAML or code. Compiling a binding expression generates compiled code that will get a value from a property on the *source*, and set it on the property on the *target* that's specified in the markup. In addition, depending on the binding expression, the generated code may observe changes in the value of the *source* property and refresh the *target* property, and may push changes from the *target* back to the *source*.

::: moniker range="=net-maui-8.0"

Expand All @@ -38,14 +38,22 @@ To use compiled bindings in XAML, the `x:DataType` attribute must be set to a st
>
> In addition, compiled bindings in XAML are currently unsupported on multi-bindings.

::: moniker-end

By default, .NET MAUI doesn't produce build warnings for bindings that don't use compiled bindings, unless you've enabled NativeAOT for your app. However, you can opt into compiled bindings warnings being produced by setting the `$(MauiStrictXamlCompilation)` build property to `true` in your app's project file (*.csproj):
By default, .NET MAUI doesn't produce build warnings for XAML bindings that don't use compiled bindings. However, you can opt into compiled bindings warnings being produced by setting the `$(MauiStrictXamlCompilation)` build property to `true` in your app's project file (*.csproj):

```xml
<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>
```

::: moniker-end

::: moniker range=">=net-maui-9.0"

By default, .NET MAUI produces build warnings for XAML bindings that don't use compiled bindings.

::: moniker-end

For more information about XAML compiled bindings warnings, see [XAML compiled bindings warnings](#xaml-compiled-bindings-warnings).

### Use compiled bindings in XAML

The following example demonstrates using compiled bindings between .NET MAUI views and viewmodel properties:
Expand Down Expand Up @@ -77,7 +85,7 @@ The following example demonstrates using compiled bindings between .NET MAUI vie
</ContentPage>
```

The <xref:Microsoft.Maui.Controls.ContentPage> instantiates the `HslColorViewModel` and initializes the `Color` property within property element tags for the `BindingContext` property. The <xref:Microsoft.Maui.Controls.ContentPage> also defines the `x:DataType` attribute as the viewmodel type, indicating that any binding expressions in the <xref:Microsoft.Maui.Controls.ContentPage> view hierarchy will be compiled. This can be verified by changing any of the binding expressions to bind to a non-existent viewmodel property, which will result in a build error. While this example sets the `x:DataType` attribute to a string literal, it can also be set to a type with the `x:Type` markup extension. For more information about the `x:Type` markup extension, see [x:Type Markup Extension](~/xaml/markup-extensions/consume.md#xtype-markup-extension).
The <xref:Microsoft.Maui.Controls.ContentPage> instantiates the `HslColorViewModel` and initializes the `Color` property within property element tags for the <xref:Microsoft.Maui.Controls.BindableObject.BindingContext> property. The <xref:Microsoft.Maui.Controls.ContentPage> also defines the `x:DataType` attribute as the viewmodel type, indicating that any binding expressions in the <xref:Microsoft.Maui.Controls.ContentPage> view hierarchy will be compiled. This can be verified by changing any of the binding expressions to bind to a non-existent viewmodel property, which will result in a build error. While this example sets the `x:DataType` attribute to a string literal, it can also be set to a type with the `x:Type` markup extension. For more information about the `x:Type` markup extension, see [x:Type Markup Extension](~/xaml/markup-extensions/consume.md#xtype-markup-extension).

> [!IMPORTANT]
> The `x:DataType` attribute can be re-defined at any point in a view hierarchy.
Expand All @@ -92,9 +100,24 @@ For more information about this color selector, see [ViewModels and property-cha

### Use compiled bindings in XAML in a DataTemplate

Bindings in a <xref:Microsoft.Maui.Controls.DataTemplate> are interpreted in the context of the object being templated. Therefore, when using compiled bindings in a <xref:Microsoft.Maui.Controls.DataTemplate>, the <xref:Microsoft.Maui.Controls.DataTemplate> needs to declare the type of its data object using the `x:DataType` attribute.
Bindings in a <xref:Microsoft.Maui.Controls.DataTemplate> are interpreted in the context of the object being templated. Therefore, when using compiled bindings in a <xref:Microsoft.Maui.Controls.DataTemplate>, the <xref:Microsoft.Maui.Controls.DataTemplate> needs to declare the type of its data object using the `x:DataType` attribute. Failure to do this could result in the <xref:Microsoft.Maui.Controls.DataTemplate> inheriting an incorrect `x:DataType` from its parent scope:

```xaml
<ContentPage ...
x:DataType="local:AnimalsPageViewModel">
<!-- Binding to AnimalsPageViewModel.Animals -->
<CollectionView ItemsSource="{Binding Animals}">
<CollectionView.ItemTemplate>
<DataTemplate>
<!-- incorrect: compiler thinks you want to bind to AnimalsPageViewModel.Name -->
<Label Text="{Binding Name}" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>
```

The following example demonstrates using compiled bindings in a <xref:Microsoft.Maui.Controls.DataTemplate>:
The following example demonstrates correctly setting the `x:DataType` on a <xref:Microsoft.Maui.Controls.DataTemplate>:

```xaml
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
Expand Down Expand Up @@ -137,6 +160,27 @@ When the example is first run, the <xref:Microsoft.Maui.Controls.ListView> is po

Selecting other items in the <xref:Microsoft.Maui.Controls.ListView> updates the color of the <xref:Microsoft.Maui.Controls.BoxView>.

::: moniker range=">=net-maui-9.0"

### Compile bindings that define the `Source` property

Prior to .NET MAUI 9, the XAML compiler would skip compilation of bindings that define the `Source` property instead of the <xref:Microsoft.Maui.Controls.BindableObject.BindingContext>. From .NET MAUI 9, these bindings can be compiled to take advantage of better runtime performance. However, this optimization isn't enabled by default to avoid breaking existing app code. To enable this optimization, set the `$(MauiEnableXamlCBindingWithSourceCompilation)` build property to `true` in your app's project file:

```xml
<MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation>
```

Then, ensure that all your bindings are annotated with the correct `x:DataType` and that they don't inherit incorrect data types from their parent scope:

```xaml
<HorizontalStackLayout BindingContext="{x:Reference slider}" x:DataType="Slider">
<Label Text="{Binding Value}" />
<Label Text="{Binding Text, Source={x:Reference entry}, x:DataType=Entry}" />
</HorizontalStackLayout>
```

::: moniker-end

### Combine compiled bindings with classic bindings in XAML

Binding expressions are only compiled for the view hierarchy that the `x:DataType` attribute is defined on. Conversely, any views in a hierarchy on which the `x:DataType` attribute is not defined will use classic bindings. It's therefore possible to combine compiled bindings and classic bindings on a page. For example, in the previous section the views within the <xref:Microsoft.Maui.Controls.DataTemplate> use compiled bindings, while the <xref:Microsoft.Maui.Controls.BoxView> that's set to the color selected in the <xref:Microsoft.Maui.Controls.ListView> does not.
Expand Down Expand Up @@ -167,6 +211,65 @@ The root <xref:Microsoft.Maui.Controls.StackLayout> sets the `x:DataType` attrib

For more information about the `x:Null` markup expression, see [x:Null Markup Extension](~/xaml/markup-extensions/consume.md#xnull-markup-extension).

### XAML compiled bindings warnings

The following table lists the compiler warnings for compiled bindings, and how to resolve them:

::: moniker range="=net-maui-8.0"

| Code | Message | Fix |
| ---- | ------- | --- |
| `XC0022` | Binding could be compiled to improve runtime performance if `x:DataType` is specified. | Add `x:DataType` to your XAML to specify the type of the current <xref:Microsoft.Maui.Controls.BindableObject.BindingContext>. It's best practice to add `x:DataType` to all elements where the binding context changes. |
| `XC0023` | Binding could be compiled to improve runtime performance if `x:DataType` is not explicitly `null`. | Replace `x:DataType="{x:Null}"` with the right type. |

::: moniker-end

::: moniker range=">=net-maui-9.0"

| Code | Message |
| ---- | ------- |
| `XC0022` | Binding could be compiled to improve runtime performance if `x:DataType` is specified. <br><br>To fix this warning, add `x:DataType` to your XAML to specify the type of the current <xref:Microsoft.Maui.Controls.BindableObject.BindingContext>. It's best practice to add `x:DataType` to all elements where the binding context changes. |
| `XC0023` | Binding could be compiled to improve runtime performance if `x:DataType` is not explicitly `null`. <br><br>To fix this warning, replace `x:DataType="{x:Null}"` with the right type. |
| `XC0024` | Binding might be compiled incorrectly since the `x:DataType` annotation comes from an outer scope. Make sure you annotate all `DataTemplate` XAML elements with the correct `x:DataType`. <br><br>To fix this warning, ensure that all `DataTemplate` elements are annotated with the correct `x:DataType`. |
| `XC0025` | Binding was not compiled because it has an explicitly set `Source` property and compilation of bindings with `Source` is not enabled. Consider enabling this optimization by setting the `<MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation>` in your project file and make sure the correct `x:DataType` is specified for this binding. <br><br>To fix this warning, enable the `$(MauiEnableXamlCBindingWithSourceCompilation)` build property in your project file, and annotate all your bindings with the appropriate `x:DataType`. |

::: moniker-end

To ensure these warnings aren't ignored, consider changing specific warnings to build errors with the `$(WarningsAsErrors)` build property:

```xml
<WarningsAsErrors>$(WarningsAsErrors);XC0022;XC0023</WarningsAsErrors>
```

To ignore these warnings, use the `$(NoWarn)` build property with specific warning codes:

```xml
<NoWarn>$(NoWarn);XC0022;XC0023</NoWarn>
```

::: moniker range="=net-maui-8.0"

> [!IMPORTANT]
> `XC0022` and `XC0023` warnings will always be suppressed unless the `$(MauiStrictXamlCompilation)` build property is set to `true`.

::: moniker-end

If you set the `$(TreatWarningsAsErrors)` build property to `true` in your app's project file, but you want to ignore certain XAML compiler warnings, use either the `$(NoWarn)` build property to silence these warnings or the `$(WarningsNotAsErrors)` build property to reduce the severity of some specific codes.

::: moniker range=">=net-maui-9.0"

By default, .NET MAUI produces build warnings for XAML bindings that don't use compiled bindings. You can opt into compiled bindings warnings being treated as errors by setting the `$(MauiStrictXamlCompilation)` and `$(TreatWarningsAsErrors)` build properties to `true` in your app's project file (*.csproj):

```xml
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>
```

> [!NOTE]
> By default, the `$(MauiStrictXamlCompilation)` build property is `false` unless you are publishing your app using full trimming or NativeAOT.

::: moniker-end

::: moniker range=">=net-maui-9.0"

## Compiled bindings in code
Expand Down Expand Up @@ -230,7 +333,7 @@ Compiled bindings improve data binding performance, with the performance benefit

- A compiled binding that uses property-change notification (i.e. a `OneWay`, `OneWayToSource`, or `TwoWay` binding) is resolved approximately 8 times quicker than a classic binding.
- A compiled binding that doesn't use property-change notification (i.e. a `OneTime` binding) is resolved approximately 20 times quicker than a classic binding.
- Setting the `BindingContext` on a compiled binding that uses property change notification (i.e. a `OneWay`, `OneWayToSource`, or `TwoWay` binding) is approximately 5 times quicker than setting the `BindingContext` on a classic binding.
- Setting the `BindingContext` on a compiled binding that doesn't use property change notification (i.e. a `OneTime` binding) is approximately 7 times quicker than setting the `BindingContext` on a classic binding.
- Setting the <xref:Microsoft.Maui.Controls.BindableObject.BindingContext> on a compiled binding that uses property change notification (i.e. a `OneWay`, `OneWayToSource`, or `TwoWay` binding) is approximately 5 times quicker than setting the <xref:Microsoft.Maui.Controls.BindableObject.BindingContext> on a classic binding.
- Setting the <xref:Microsoft.Maui.Controls.BindableObject.BindingContext> on a compiled binding that doesn't use property change notification (i.e. a `OneTime` binding) is approximately 7 times quicker than setting the <xref:Microsoft.Maui.Controls.BindableObject.BindingContext> on a classic binding.

These performance differences can be magnified on mobile devices, dependent upon the platform being used, the version of the operating system being used, and the device on which the application is running.
14 changes: 7 additions & 7 deletions docs/whats-new/dotnet-9.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: What's new in .NET MAUI for .NET 9
description: Learn about the new features introduced in .NET MAUI for .NET 9.
ms.date: 10/04/2024
ms.date: 10/08/2024
---

# What's new in .NET MAUI for .NET 9
Expand Down Expand Up @@ -274,13 +274,9 @@ myEntry.SetBinding(Entry.TextProperty, new MultiBinding

## Compiled bindings in XAML

In .NET MAUI 8, compiled bindings are disabled for any XAML binding expressions that define the `Source` property, and are unsupported on multi-bindings. These restrictions have been removed in .NET MAUI 9.
In .NET MAUI 8, compiled bindings are disabled for any XAML binding expressions that define the `Source` property, and are unsupported on multi-bindings. These restrictions have been removed in .NET MAUI 9. For information about compiling XAML binding expressions that define the `Source` property, see [Compile bindings that define the `Source` property](~/fundamentals/data-binding/compiled-bindings.md?view=net-maui-9.0&preserve-view=true#compile-bindings-that-define-the-source-property).

By default, .NET MAUI doesn't produce build warnings for bindings that don't use compiled bindings, unless you've enabled NativeAOT for your app. However, you can opt into compiled bindings warnings being produced by setting the `$(MauiStrictXamlCompilation)` build property to `true` in your app's project file (*.csproj):

```xml
<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>
```
By default, .NET MAUI 9 produces build warnings for bindings that don't use compiled bindings. For more information about XAML compiled bindings warnings, see [XAML compiled bindings warnings](~/fundamentals/data-binding/compiled-bindings.md?view=net-maui-9.0&preserve-view=true#xaml-compiled-bindings-warnings).

## Handler disconnection

Expand Down Expand Up @@ -409,6 +405,10 @@ Several areas of .NET MAUI come with trimmer directives, known as feature switch

To consume a feature switch you should put the corresponding MSBuild property into your app's project file (*.csproj), which causes the related code to be trimmed from the .NET MAUI assemblies. Disabling features an app doesn't require can help reduce the app size when combined with the `Full` trimming mode.

## XAML compiler

In .NET MAUI 9, the XAML compiler error codes have changed their prefix from `XFC` to `XC`. Ensure that you update the `$(WarningsAsErrors)`, `$(WarningsNotAsErrors)`, and `$(NoWarn)` build properties in your app's project files, if used, to reference the new prefix.

## XAML markup extensions

All classes that implement <xref:Microsoft.Maui.Controls.Xaml.IMarkupExtension>, <xref:Microsoft.Maui.Controls.Xaml.IMarkupExtension`1>, <xref:Microsoft.Maui.Controls.Xaml.IValueProvider>, and <xref:Microsoft.Maui.Controls.IExtendedTypeConverter> need to be annotated with either the <xref:Microsoft.Maui.Controls.Xaml.RequireServiceAttribute> or <xref:Microsoft.Maui.Controls.Xaml.AcceptEmptyServiceProviderAttribute>. This is required due to a XAML compiler optimization introduced in .NET MAUI 9 that enables the generation of more efficient code, which helps reduce the app size and improve runtime performance.
Expand Down
Loading