BindableLayout
Los diseños enlazables de .NET Multi-platform App UI (.NET MAUI) permiten que cualquier clase de diseño que derive de la clase Layout genere su contenido mediante el enlace a una colección de elementos, con la opción de establecer la apariencia de cada elemento con un DataTemplate.
La clase proporciona BindableLayout diseños enlazables y expone las siguientes propiedades adjuntas:
ItemsSource
, que especifica la colección de elementosIEnumerable
que va a mostrar el diseño.ItemTemplate
, que especifica el DataTemplate que se aplicará a cada elemento de la colección de elementos que mostrará el diseño.ItemTemplateSelector
, que espeficia el DataTemplateSelector que se usará para elegir un DataTemplate para un elemento en tiempo de ejecución.
Nota:
Si estableces las propiedades ItemTemplate
y ItemTemplateSelector
, la prioridad la tiene la propiedad ItemTemplate
.
Además, la clase BindableLayout expone las siguientes propiedades enlazables:
EmptyView
, que especificastring
o la vista o que se mostrará cuando la propiedadItemsSource
seanull
o cuando la colección especificada por la propiedadItemsSource
seanull
o esté vacía. El valor predeterminado esnull
.EmptyViewTemplate
, que especifica que DataTemplate se mostrará cuando la propiedadItemsSource
seanull
o cuando la colección especificada por la propiedadItemsSource
seanull
o esté vacía. El valor predeterminado esnull
.
Nota:
Si estableces las propiedades EmptyView
y EmptyViewTemplate
, la prioridad la tiene la propiedad EmptyViewTemplate
.
Todas estas propiedades se pueden adjuntar a las clases AbsoluteLayout, FlexLayout, Grid, HorizontalStackLayout, StackLayout y VerticalStackLayout, que derivan de la clase Layout.
Cuando la propiedad BindableLayout.ItemsSource
se establece en una colección de elementos y se adjunta a una clase derivada de Layout, cada elemento de la colección se agrega a la clase derivada de Layout para mostrarla. Luego, la clase derivada de Layout actualizará sus vistas secundarias cuando cambie la colección subyacente.
Los diseños enlazables solo deben usarse cuando la colección de elementos que se va a mostrar es pequeña y no es necesario desplazarse ni seleccionar. Aunque el desplazamiento se puede proporcionar ajustando un diseño enlazable en ScrollView, no se recomienda porque los diseños enlazables carecen de virtualización de interfaz de usuario. Cuando se requiere el desplazamiento, se debe usar una vista desplazable que incluya virtualización de interfaz de usuario, como ListView o CollectionView. El incumplimiento de esta recomendación puede provocar problemas de rendimiento.
Importante
Aunque técnicamente es posible adjuntar un diseño enlazable a cualquier clase de diseño que derive de la clase Layout, no siempre resulta práctico hacerlo, especialmente para las clases AbsoluteLayout y Grid. Por ejemplo, piensa en un escenario en el que se quiere mostrar una colección de datos en un Grid mediante un diseño enlazable, donde cada elemento de la colección es un objeto que contiene varias propiedades. Cada fila de Grid debe mostrar un objeto de la colección, y cada columna de Grid muestra una de las propiedades del objeto. Dado que el DataTemplate para el diseño enlazable solo puede contener un objeto, es necesario que ese objeto sea una clase de diseño que contenga varias vistas y que cada vista muestre una de las propiedades del objeto en una columna Grid específica. Aunque este escenario se puede cumplir con diseños enlazables, da como resultado un Grid primario que contiene un Grid secundario para cada elemento de la colección enlazada, lo que supone un uso altamente ineficaz y cuestionable del diseño Grid.
Rellenar un diseño enlazable con datos
Un diseño enlazable se rellena con datos estableciendo su propiedad ItemsSource
en cualquier colección que implemente IEnumerable
y adjuntándola a una clase derivada de Layout:
<Grid BindableLayout.ItemsSource="{Binding Items}" />
El código de C# equivalente es el siguiente:
IEnumerable<string> items = ...;
Grid grid = new Grid();
BindableLayout.SetItemsSource(grid, items);
Cuando se establece la propiedad adjunta BindableLayout.ItemsSource
en un diseño, pero no se establece la propiedad adjunta BindableLayout.ItemTemplate
, cada elemento de la colección IEnumerable
se mostrará mediante un objeto Label creado por la clase BindableLayout.
Definición de la apariencia de elementos
La apariencia de cada elemento del diseño enlazable se puede definir estableciendo la propiedad adjunta BindableLayout.ItemTemplate
en un objeto DataTemplate:
<StackLayout BindableLayout.ItemsSource="{Binding User.TopFollowers}"
Orientation="Horizontal"
...>
<BindableLayout.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"
Aspect="AspectFill"
WidthRequest="44"
HeightRequest="44"
... />
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
El código de C# equivalente es el siguiente:
DataTemplate imageTemplate = ...;
StackLayout stackLayout = new StackLayout();
BindableLayout.SetItemsSource(stackLayout, viewModel.User.TopFollowers);
BindableLayout.SetItemTemplate(stackLayout, imageTemplate);
En este ejemplo, cada elemento de la colección TopFollowers
se mostrará mediante una vista Image definida en el objeto DataTemplate:
Para obtener más información sobre las plantillas de datos, consulta Plantillas de datos.
Elección de la apariencia del elemento en tiempo de ejecución
La apariencia de cada elemento del diseño enlazable se puede elegir en tiempo de ejecución, en función del valor del elemento, estableciendo la propiedad BindableLayout.ItemTemplateSelector
adjunta en un objeto DataTemplateSelector:
<FlexLayout BindableLayout.ItemsSource="{Binding User.FavoriteTech}"
BindableLayout.ItemTemplateSelector="{StaticResource TechItemTemplateSelector}"
... />
El código de C# equivalente es el siguiente:
DataTemplateSelector dataTemplateSelector = new TechItemTemplateSelector { ... };
FlexLayout flexLayout = new FlexLayout();
BindableLayout.SetItemsSource(flexLayout, viewModel.User.FavoriteTech);
BindableLayout.SetItemTemplateSelector(flexLayout, dataTemplateSelector);
En el ejemplo siguiente se muestra la clase TechItemTemplateSelector
:
public class TechItemTemplateSelector : DataTemplateSelector
{
public DataTemplate DefaultTemplate { get; set; }
public DataTemplate MAUITemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return (string)item == ".NET MAUI" ? MAUITemplate : DefaultTemplate;
}
}
La clase TechItemTemplateSelector
define DefaultTemplate
y MAUITemplate
DataTemplate propiedades que se establecen en diferentes plantillas de datos. El método OnSelectTemplate
devuelve MAUITemplate
, que muestra un elemento en rojo oscuro con un corazón a su lado, cuando el elemento es igual a ".NET MAUI". Cuando el elemento no es igual a ".NET MAUI", el método OnSelectTemplate
devuelve DefaultTemplate
, que muestra un elemento con el color predeterminado de Label:
Para más información sobre los selectores de plantillas de datos, consulta Creación de DataTemplateSelector.
Mostrar una cadena cuando los datos no están disponibles
La propiedad EmptyView
se puede establecer en una cadena, que se mostrará mediante Label cuando la propiedad ItemsSource
sea null
o cuando la colección especificada por la propiedad ItemsSource
sea null
o esté vacía. En el siguiente archivo XAML se muestra un ejemplo de este escenario:
<StackLayout BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}"
BindableLayout.EmptyView="No achievements">
...
</StackLayout>
El resultado es que, cuando la colección enlazada a datos es null
, se muestra el conjunto de cadenas como valor de propiedad EmptyView
:
Muestra de vistas cuando los datos no están disponibles
La propiedad EmptyView
se puede establecer en una vista, que se mostrará cuando la propiedad ItemsSource
sea null
, o cuando la colección especificada por la propiedad ItemsSource
sea null
o esté vacía. Puede ser una sola vista o una vista que contenga varias vistas secundarias. En el ejemplo de XAML siguiente se muestra la propiedad EmptyView
establecida en una vista que contiene varias vistas secundarias:
<StackLayout BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}">
<BindableLayout.EmptyView>
<StackLayout>
<Label Text="None."
FontAttributes="Italic"
FontSize="{StaticResource smallTextSize}" />
<Label Text="Try harder and return later?"
FontAttributes="Italic"
FontSize="{StaticResource smallTextSize}" />
</StackLayout>
</BindableLayout.EmptyView>
...
</StackLayout>
El resultado es que, cuando la colección enlazada a datos es null
, se muestran StackLayout y sus vistas secundarias.
Del mismo modo, EmptyViewTemplate
se puede establecer en DataTemplate, que se mostrará cuando la propiedad ItemsSource
sea null
o cuando la colección especificada por la propiedad ItemsSource
sea null
o esté vacía. DataTemplate puede contener una sola vista o una vista que contenga varias vistas secundarias. Además, BindingContext
de EmptyViewTemplate
se heredará de BindingContext
de BindableLayout. En el ejemplo XAML siguiente se muestra la propiedad EmptyViewTemplate
establecida en DataTemplate que contiene una sola vista:
<StackLayout BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}">
<BindableLayout.EmptyViewTemplate>
<DataTemplate>
<Label Text="{Binding Source={x:Reference usernameLabel}, Path=Text, StringFormat='{0} has no achievements.'}" />
</DataTemplate>
</BindableLayout.EmptyViewTemplate>
...
</StackLayout>
El resultado es que cuando la colección enlazada a datos es null
, se muestra Label en DataTemplate:
Nota:
La propiedad EmptyViewTemplate
no se puede establecer mediante DataTemplateSelector.
Elección de emptyView en tiempo de ejecución
Las vistas que se mostrarán como EmptyView
cuando los datos no estén disponibles, se pueden definir como objetos ContentView en un ResourceDictionary. Luego, la propiedad EmptyView
se puede establecer en un elemento ContentView específico, en función de alguna lógica de negocios, en tiempo de ejecución. En el siguiente archivo XAML se muestra un ejemplo de este escenario:
<ContentPage ...>
<ContentPage.Resources>
...
<ContentView x:Key="BasicEmptyView">
<StackLayout>
<Label Text="No achievements."
FontSize="14" />
</StackLayout>
</ContentView>
<ContentView x:Key="AdvancedEmptyView">
<StackLayout>
<Label Text="None."
FontAttributes="Italic"
FontSize="14" />
<Label Text="Try harder and return later?"
FontAttributes="Italic"
FontSize="14" />
</StackLayout>
</ContentView>
</ContentPage.Resources>
<StackLayout>
...
<Switch Toggled="OnEmptyViewSwitchToggled" />
<StackLayout x:Name="stackLayout"
BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}">
...
</StackLayout>
</StackLayout>
</ContentPage>
El XAML define dos objetos ContentView en el nivel de página ResourceDictionary, con el objeto Switch que controla qué objeto ContentView se establecerá como valor de propiedad EmptyView
. Switch Cuando está activado, el controlador de eventos OnEmptyViewSwitchToggled
ejecuta el método ToggleEmptyView
:
void ToggleEmptyView(bool isToggled)
{
object view = isToggled ? Resources["BasicEmptyView"] : Resources["AdvancedEmptyView"];
BindableLayout.SetEmptyView(stackLayout, view);
}
El método ToggleEmptyView
establece la propiedad EmptyView
del objeto StackLayout en uno de los dos objetos ContentView almacenados en ResourceDictionary, en función del valor de la propiedad Switch.IsToggled
. A continuación, cuando la colección enlazada a datos es null
, se muestra el objeto ContentView establecido como la propiedad EmptyView
.