Enlaces compilados
Los enlaces de datos de.NET Multi-platform App UI (.NET MAUI) tienen dos problemas principales:
- No hay ninguna validación de las expresiones de enlace en tiempo de compilación. Alternativamente, los enlaces se resuelven en tiempo de ejecución. Por lo tanto, los enlaces no válidos no se detectan hasta el tiempo de ejecución, cuando la aplicación no se comporta según lo esperado o aparecen mensajes de error.
- No son rentables. Los enlaces se resuelven en tiempo de ejecución mediante la inspección de objetos de uso general (reflejo); el trabajo adicional que supone llevarlo a cabo varía en función de la plataforma.
Los enlaces compilados mejoran el rendimiento del enlace de datos en las aplicaciones .NET MAUI mediante la resolución de expresiones de enlace en tiempo de compilación, en lugar de en tiempo de ejecución. Además, esta validación en tiempo de compilación de expresiones de enlace permite una mejor experiencia de solución de problemas, porque los enlaces no válidos se notifican como errores de compilación.
Importante
Los enlaces compilados son necesarios en lugar de enlaces basados en cadenas en aplicaciones NativeAOT y en aplicaciones con recorte completo habilitado. Para obtener más información, consulte Recorte de una aplicación MAUI de .NET y implementación de AOT nativa.
Enlaces compilados en XAML
Para usar enlaces vinculados en XAML, establece un atributo x:DataType
en un VisualElement para el tipo del objeto al que VisualElement y sus elementos secundarios se enlazarán. Se recomienda establecer el atributo x:DataType
en el mismo nivel de la jerarquía de vistas en que está establecido BindingContext. Sin embargo, este atributo puede volver a definirse en cualquier ubicación en una jerarquía de vistas.
Importante
Los enlaces compilados requieren el uso de la compilación de XAML, que está habilitada de forma predeterminada en .NET MAUI. Si has deshabilitado la compilación de XAML, deberás habilitarla. Para obtener más información, consulte Compilación XAML.
Para usar enlaces compilados en XAML, el atributo x:DataType
debe establecerse en un literal de cadena o un tipo con la extensión de marcado x:Type
. En tiempo de compilación XAML, las expresiones de enlace no válidas se notificarán como errores de compilación. Sin embargo, el compilador XAML solo notificará un error de compilación para la primera expresión de enlace no válida que encuentre. Las expresiones de enlace válidas que se definen en VisualElement o en sus elementos secundarios se compilarán, independientemente de si BindingContext está establecido en XAML o en código. La compilación de una expresión de enlace genera un código compilado que obtendrá un valor de una propiedad en el origen y lo establecerá en la propiedad en el destino que se especifica en el marcado. Además, dependiendo de la expresión de enlace, el código generado puede observar cambios en el valor de la propiedad de origen y actualizar la propiedad de destino, y puede insertar los cambios desde el destino de nuevo al origen.
Importante
Los enlaces compilados están deshabilitados para las expresiones de enlace XAML que definen la propiedad Source
. Esto es así porque la propiedad Source
siempre se establece mediante la extensión de marcado x:Reference
, que no se puede resolver en tiempo de compilación.
Además, actualmente no se admiten enlaces compilados en XAML en enlaces múltiples.
De forma predeterminada, .NET MAUI no genera advertencias de compilación para enlaces XAML que no usan enlaces compilados. Sin embargo, puedes optar por generar advertencias de enlaces compilados estableciendo la propiedad de compilación $(MauiStrictXamlCompilation)
en true
en el archivo de proyecto de la aplicación (*.csproj):
<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>
De forma predeterminada, .NET MAUI genera advertencias de compilación para enlaces XAML que no usan enlaces compilados.
Para obtener más información sobre las advertencias de enlaces compilados XAML, consulta Advertencias de enlaces compilados XAML.
Uso de enlaces compilados en XAML
En el ejemplo siguiente se muestra el uso de enlaces compilados entre las vistas de .NET MAUI y las propiedades del modelo de vista:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.CompiledColorSelectorPage"
x:DataType="local:HslColorViewModel"
Title="Compiled Color Selector">
<ContentPage.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</ContentPage.BindingContext>
...
<StackLayout>
<BoxView Color="{Binding Color}"
... />
<StackLayout Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Hue}" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
<Slider Value="{Binding Saturation}" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
<Slider Value="{Binding Luminosity}" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>
</ContentPage>
ContentPage crea una instancia de HslColorViewModel
e inicializa la propiedad Color
dentro de las etiquetas de elemento de propiedad para la propiedad BindingContext.
ContentPage también define el atributo x:DataType
como el tipo de modelo de vista, lo que indica que todas las expresiones de enlace en la jerarquía de vistas ContentPage se compilarán. Esto se puede comprobar cambiando cualquiera de las expresiones de enlace para enlazar a una propiedad ViewModel inexistente, lo cual generará a un error de compilación. Aunque en este ejemplo se establece el atributo x:DataType
en un literal de cadena, también se puede establecer en un tipo con la extensión de marcado x:Type
. Para obtener más información acerca de la extensión de marcado x:Type
, consulte x:Type Markup Extension (Extensión de marcado x:Type).
Importante
El atributo x:DataType
puede volver a definirse en cualquier punto de una jerarquía de vistas.
Los elementos BoxView, Label y las vistas Slider heredan el contexto de enlace del elemento ContentPage. Todas estas vistas son destinos de enlace que hacen referencia a las propiedades de origen en el modelo de vista. Para la propiedad BoxView.Color
y la propiedad Label.Text
, los enlaces de datos son OneWay
; las propiedades de las vista se establecen a partir de las propiedades en ViewModel. Sin embargo, la propiedad Slider.Value
utiliza un enlace TwoWay
. Esto permite que cada elemento Slider se establezca a partir del modelo de vista, y también que el modelo de vista se establezca a partir de cada elemento Slider.
Cuando la aplicación se ejecuta por primera vez, los elementos BoxView, Label y los elementos Slider se establecen todos a partir del modelo de vista basado en la propiedad Color
inicial establecida cuando se creó una instancia del modelo de vista. A medida que se manipulan los controles deslizantes, los elementos BoxView y Label se actualizan del modo correspondiente:
Para obtener más información acerca de este selector de colores, consulta Modelos de vista y notificaciones de cambio de propiedad.
Uso de enlaces compilados en XAML en una DataTemplate
Los enlaces en DataTemplate se interpretan en el contexto del objeto del cual se crea la plantilla. Por lo tanto, cuando utilice enlaces de compilación en DataTemplate, DataTemplate debe declarar el tipo de su objeto de datos mediante el atributo x:DataType
. Si no se hace esto, se podría producir un DataTemplate error al heredar un valor incorrecto x:DataType
de su ámbito primario:
<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>
En el ejemplo siguiente se muestra cómo establecer correctamente en x:DataType
:DataTemplate
<ContentPage ...
x:DataType="local:AnimalsPageViewModel">
<!-- Binding to AnimalsPageViewModel.Animals -->
<CollectionView ItemsSource="{Binding Animals}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="local:Animal">
<!-- correct: compiler knows you want to bind to Animal.Name -->
<Label Text="{Binding Name}" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>
Aunque en este ejemplo se establece el atributo x:DataType
en un literal de cadena, también se puede establecer en un tipo con la extensión de marcado x:Type
. Para obtener más información acerca de la extensión de marcado x:Type
, consulte x:Type Markup Extension (Extensión de marcado x:Type).
Compilar enlaces que definen la Source
propiedad
Antes de .NET MAUI 9, el compilador XAML omitiría la compilación de enlaces que definen la Source
propiedad en lugar de BindingContext. A partir de .NET MAUI 9, estos enlaces se pueden compilar para aprovechar el mejor rendimiento en tiempo de ejecución. Sin embargo, esta optimización no está habilitada de forma predeterminada para evitar interrumpir el código de aplicación existente. Para habilitar esta optimización, establezca la propiedad $(MauiEnableXamlCBindingWithSourceCompilation)
build en el true
archivo de proyecto de la aplicación:
<MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation>
A continuación, asegúrese de que todos los enlaces se anotan con el correcto x:DataType
y que no heredan tipos de datos incorrectos de su ámbito primario:
<HorizontalStackLayout BindingContext="{x:Reference slider}" x:DataType="Slider">
<Label Text="{Binding Value}" />
<Label Text="{Binding Text, Source={x:Reference entry}, x:DataType=Entry}" />
</HorizontalStackLayout>
Nota:
En los casos en los que hay un enlace con , Source
pero hereda del x:DataType
elemento primario, puede haber una discrepancia entre y x:DataType
el tipo de Source
. En este escenario, se generará una advertencia y se producirá una reserva en un enlace basado en reflexión que resuelva la ruta de acceso de enlace en tiempo de ejecución.
Combinación de enlaces compilados con enlaces clásicos en XAML
Las expresiones de enlace solo se compilan para la jerarquía de vistas en la cual está definido el atributo x:DataType
. Por contra, todas las vistas en una jerarquía en la cual el atributo x:DataType
no esté definido utilizarán enlaces clásicos. Por lo tanto, es posible combinar enlaces compilados y enlaces clásicos en una página. Por ejemplo, en la sección anterior, las vistas dentro de DataTemplate utilizan enlaces compilados, mientras que el elemento BoxView que se establece en el color seleccionado en ListView, no lo hace.
Una estructuración cuidadosa de atributos x:DataType
, por lo tanto, puede conseguir que una página utilice enlaces compilados y clásicos. De forma alternativa, el atributo x:DataType
se puede volver a definir en cualquier punto en una jerarquía de vistas para null
utilizando la extensión de marcado x:Null
. Esto indica que las expresiones de enlace dentro de la jerarquía de vistas utilizarán enlaces clásicos. El siguiente ejemplo demuestra este enfoque:
<StackLayout x:DataType="local:HslColorViewModel">
<StackLayout.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</StackLayout.BindingContext>
<BoxView Color="{Binding Color}"
VerticalOptions="FillAndExpand" />
<StackLayout x:DataType="{x:Null}"
Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Hue}" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
<Slider Value="{Binding Saturation}" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
<Slider Value="{Binding Luminosity}" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>
El elemento StackLayout raíz establece el atributo x:DataType
para ser del tipo HslColorViewModel
, lo cual indica que todas las expresiones de enlace en la jerarquía de vistas StackLayout se compilarán. Sin embargo, el StackLayout interno redefine el atributo x:DataType
en null
con la expresión de marcado x:Null
. Por lo tanto, las expresiones de enlace dentro del StackLayout interno usan enlaces clásicos. Solo BoxView, dentro de la jerarquía de vistas StackLayout raíz, utiliza enlaces compilados.
Para obtener más información acerca de la expresión de marcado x:Null
, consulte x:Null Markup Extension (Extensión de marcado x:Null).
Advertencias de enlaces compilados xaml
En la tabla siguiente se enumeran las advertencias del compilador para los enlaces compilados y cómo resolverlas:
Código | Message | Fix |
---|---|---|
XC0022 |
El enlace se podría compilar para mejorar el rendimiento en tiempo de ejecución si x:DataType se especifica. |
Agregue x:DataType a xaml para especificar el tipo del objeto actual BindingContext. Se recomienda agregar x:DataType a todos los elementos en los que cambia el contexto de enlace. |
XC0023 |
El enlace se podría compilar para mejorar el rendimiento del entorno de ejecución si x:DataType no es explícitamente null . |
Reemplace por x:DataType="{x:Null}" el tipo correcto. |
Código | Message |
---|---|
XC0022 |
El enlace se podría compilar para mejorar el rendimiento en tiempo de ejecución si x:DataType se especifica. Para corregir esta advertencia, agregue x:DataType a xaml para especificar el tipo del objeto actual BindingContext. Se recomienda agregar x:DataType a todos los elementos en los que cambia el contexto de enlace. |
XC0023 |
El enlace se podría compilar para mejorar el rendimiento del entorno de ejecución si x:DataType no es explícitamente null . Para corregir esta advertencia, reemplace x:DataType="{x:Null}" por el tipo correcto. |
XC0024 |
El enlace puede compilarse incorrectamente, ya que la x:DataType anotación procede de un ámbito externo. Asegúrate de anotar todos los DataTemplate elementos XAML con el correcto x:DataType . Para corregir esta advertencia, asegúrese de que todos los DataTemplate elementos se anotan con el correcto x:DataType . |
XC0025 |
No se compiló el enlace porque tiene una propiedad establecida Source explícitamente y la compilación de enlaces con Source no está habilitada. Considere la posibilidad de habilitar esta optimización estableciendo el en el <MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation> archivo del proyecto y asegúrese de que se especifica el valor correcto x:DataType para este enlace. Para corregir esta advertencia, habilite la propiedad build en el $(MauiEnableXamlCBindingWithSourceCompilation) archivo del proyecto y anote todos los enlaces con el adecuado x:DataType . |
Para asegurarse de que estas advertencias no se omiten, considere la posibilidad de cambiar advertencias específicas para generar errores con la $(WarningsAsErrors)
propiedad build:
<WarningsAsErrors>$(WarningsAsErrors);XC0022;XC0023</WarningsAsErrors>
Para omitir estas advertencias, use la $(NoWarn)
propiedad build con códigos de advertencia específicos:
<NoWarn>$(NoWarn);XC0022;XC0023</NoWarn>
Importante
XC0022
Las advertencias y XC0023
siempre se suprimirán a menos que la $(MauiStrictXamlCompilation)
propiedad de compilación esté establecida en true
.
Si estableces la propiedad $(TreatWarningsAsErrors)
de compilación en el true
archivo de proyecto de la aplicación, pero quieres omitir determinadas advertencias del compilador XAML, usa la $(NoWarn)
propiedad build para silenciar estas advertencias o la $(WarningsNotAsErrors)
propiedad de compilación para reducir la gravedad de algunos códigos específicos.
De forma predeterminada, .NET MAUI genera advertencias de compilación para enlaces XAML que no usan enlaces compilados. Puede participar en advertencias de enlaces compilados que se tratan como errores estableciendo las $(MauiStrictXamlCompilation)
propiedades $(TreatWarningsAsErrors)
de compilación y true
en en el archivo de proyecto de la aplicación (*.csproj):
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>
Nota:
De forma predeterminada, la $(MauiStrictXamlCompilation)
propiedad build es false
a menos que esté publicando la aplicación mediante el recorte completo o NativeAOT.
Enlaces compilados en código
Los enlaces escritos en código suelen usar rutas de acceso de cadena que se resuelven en tiempo de ejecución con reflexión. Sin embargo, el método de extensión SetBinding también tiene una sobrecarga que define los enlaces mediante un argumento Func
en lugar de una ruta de acceso de cadena:
MyLabel.SetBinding(Label.TextProperty, static (Entry entry) => entry.Text);
No todos los métodos se pueden usar para definir un enlace compilado. La expresión debe ser una expresión de acceso de propiedad simple. En los ejemplos siguientes se muestran expresiones de enlace válidas y no válidas:
// Valid: Property access
static (PersonViewModel vm) => vm.Name;
static (PersonViewModel vm) => vm.Address?.Street;
// Valid: Array and indexer access
static (PersonViewModel vm) => vm.PhoneNumbers[0];
static (PersonViewModel vm) => vm.Config["Font"];
// Valid: Casts
static (Label label) => (label.BindingContext as PersonViewModel).Name;
static (Label label) => ((PersonViewModel)label.BindingContext).Name;
// Invalid: Method calls
static (PersonViewModel vm) => vm.GetAddress();
static (PersonViewModel vm) => vm.Address?.ToString();
// Invalid: Complex expressions
static (PersonViewModel vm) => vm.Address?.Street + " " + vm.Address?.City;
static (PersonViewModel vm) => $"Name: {vm.Name}";
Advertencia
Se producirá un error del compilador CS0272 si el accesor set para una propiedad o indexador no es accesible. Si esto ocurre, aumente la accesibilidad del accesor.
Además, el método BindingBase.Create establece el enlace directamente en el objeto con Func
y devuelve la instancia del objeto de enlace:
myEntry.SetBinding(Entry.TextProperty, new MultiBinding
{
Bindings = new Collection<BindingBase>
{
Binding.Create(static (Entry entry) => entry.FontFamily, source: RelativeBindingSource.Self),
Binding.Create(static (Entry entry) => entry.FontSize, source: RelativeBindingSource.Self),
Binding.Create(static (Entry entry) => entry.FontAttributes, source: RelativeBindingSource.Self),
},
Converter = new StringConcatenationConverter()
});
Estos enfoques de enlace compilados proporcionan las siguientes ventajas:
- Mejora del rendimiento del enlace de datos mediante la resolución de expresiones de enlace en tiempo de compilación, en lugar de en tiempo de ejecución.
- Una mejor experiencia de solución de problemas para el desarrollador, ya que los enlaces no válidos se notifican como errores de compilación.
- IntelliSense durante la edición.
Rendimiento
Los enlaces compilados mejoran el rendimiento de los enlaces de datos, aunque la ventaja de rendimiento varía:
- Un enlace compilado que utiliza la notificación de cambio de propiedad (es decir, un enlace
OneWay
,OneWayToSource
oTwoWay
) se resuelve aproximadamente 8 veces más rápidamente que un enlace clásico. - Un enlace compilado que no utiliza la notificación de cambio de propiedad (es decir, un enlace
OneTime
) se resuelve aproximadamente 20 veces más rápidamente que un enlace clásico. - El establecimiento de BindingContext en un enlace compilado que utiliza la notificación de cambio de propiedad (es decir, un enlace
OneWay
,OneWayToSource
oTwoWay
) se resuelve aproximadamente 5 veces más rápidamente que el establecimiento de BindingContext en un enlace clásico. - El establecimiento de BindingContext en un enlace compilado que no utiliza la notificación de cambio de propiedad (es decir, un enlace
OneTime
) se resuelve aproximadamente 7 veces más rápidamente que el establecimiento de BindingContext en un enlace clásico.
Estas diferencias de rendimiento se pueden ampliar en dispositivos móviles, dependiendo de la plataforma que se utilice, la versión del sistema operativo que se utilice y el dispositivo en el que se ejecute la aplicación.