Share via


BindableLayout

Browse sample. Examina la muestra

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 elementos IEnumerable 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 especifica string o la vista o 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. El valor predeterminado es null.
  • EmptyViewTemplate, que especifica que DataTemplate se mostrará cuando la propiedad ItemsSource sea null o cuando la colección especificada por la propiedad ItemsSource sea null o esté vacía. El valor predeterminado es null.

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:

.NET MAUI bindable layout with a 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 las propiedades DefaultTemplate y MAUITemplate de DataTemplate que se establecen en plantillas de datos diferentes. 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:

.NET MAUI bindable layout with a DataTemplateSelector.

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:

Screenshot of a bindable layout string empty view.

Visualizar 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.

Screenshot of a bindable layout empty view with multiple views.

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:

Screenshot of a bindable layout empty view template.

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 OnEmptyViewSwitchToggledejecuta 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.