Bindbare Layouts in Xamarin.Forms

Bindungsfähige Layouts ermöglichen jede Layoutklasse, die von der Layout<T> Klasse abgeleitet wird, um ihren Inhalt zu generieren, indem sie an eine Sammlung von Elementen gebunden wird, mit der Option zum Festlegen der Darstellung der einzelnen Elemente mit einer DataTemplate. Bindbare Layouts werden von der BindableLayout-Klasse bereitgestellt, die die folgenden angefügten Eigenschaften verfügbar macht:

  • ItemsSource – gibt die Sammlung von IEnumerable-Elementen an, die vom Layout angezeigt werden sollen.
  • ItemTemplate – gibt die DataTemplate an, das auf jedes Element in der Sammlung der angezeigten Elemente angewendet werden soll.
  • ItemTemplateSelector – gibt den DataTemplateSelector an, der verwendet wird, um zur Runtime eine DataTemplate für ein Element auszuwählen.

Hinweis

Die ItemTemplate-Eigenschaft hat Vorrang, wenn sowohl die Eigenschaft ItemTemplate als auch die Eigenschaft ItemTemplateSelector festgelegt wird.

Darüber hinaus macht die BindableLayout-Klasse die folgenden bindbaren Eigenschaften verfügbar:

  • EmptyView – gibt die string oder die Ansicht an, die angezeigt wird, wenn die ItemsSource-Eigenschaft null ist, oder wenn die durch die ItemsSource-Eigenschaft angegebene Sammlung null oder leer ist. Der Standardwert ist null.
  • EmptyViewTemplate – gibt die DataTemplate-Eigenschaft an, die angezeigt wird, wenn die ItemsSource-Eigenschaft null ist, oder wenn die durch die ItemsSource-Eigenschaft angegebene Sammlung null oder leer ist. Der Standardwert ist null.

Hinweis

Wenn Sie beispielsweise die Eigenschaft EmptyView und die Eigenschaft EmptyViewTemplate festlegen, hat die Eigenschaft EmptyViewTemplate Vorrang.

Alle diese Eigenschaften können an die AbsoluteLayoutKlassen , FlexLayout, Grid, RelativeLayoutund StackLayout klassen angefügt werden, die alle von der Layout<T> Klasse abgeleitet sind.

Die Layout<T> Klasse macht eine Children Auflistung verfügbar, der die untergeordneten Elemente eines Layouts hinzugefügt werden. Wenn die BindableLayout.ItemsSource Eigenschaft auf eine Auflistung von Elementen festgelegt und an eine Layout<T>abgeleitete Klasse angefügt ist, wird jedes Element in der Auflistung zur Layout<T>.Children Anzeige durch das Layout hinzugefügt. Die Layout<T>-abgeleitete Klasse aktualisiert dann die untergeordneten Ansichten, wenn sich die zugrunde liegende Auflistung ändert. Weitere Informationen zum Xamarin.Forms Layoutzyklus finden Sie unter Erstellen eines benutzerdefinierten Layouts.

Bindende Layouts sollten nur verwendet werden, wenn die anzuzeigende Sammlung von Elementen klein ist, und kein Scrollen und Auswählen benötigt wird. Der Bildlauf kann zwar durch Umbruch eines gebundenen Layouts in einer ScrollView bereitgestellt werden, dies wird jedoch nicht empfohlen, da bindbare Layouts keine UI-Virtualisierung aufweisen. Wenn ein Bildlauf benötigt wird, sollte eine scrollbare Ansicht verwendet werden, die UI-Virtualisierung enthält, wie ListView oder CollectionView, Wenn diese Empfehlung nicht beachtet wird, kann dies zu Leistungsproblemen führen.

Wichtig

Obwohl es technisch möglich ist, ein bindungsfähiges Layout an jede Layoutklasse anzufügen, die von der Layout<T> Klasse abgeleitet wird, ist es nicht immer praktisch, dies insbesondere für die AbsoluteLayoutKlassen und RelativeLayout die Klassen Gridzu tun. Betrachten Sie z. B. das Szenario, in dem eine Sammlung von Daten durch ein gebundenes Layout in einem Grid angezeigt werden soll, wobei jedes Element in der Sammlung ein Objekt ist, das mehrere Eigenschaften enthält. Jede Zeile im Grid sollte ein Objekt aus der Sammlung anzeigen, wobei jede Spalte im Grid eine der Eigenschaften des Objekts anzeigt. Da die DataTemplate für das bindbare Layout nur ein einzelnes Objekt enthalten kann, muss es sich bei diesem Objekt um eine Layout-Klasse handeln, die mehrere Ansichten enthält, die jeweils eine der Eigenschaften des Objekts in einer bestimmten Grid-Spalte anzeigen. Dieses Szenario kann zwar mit bindbaren Layouts realisiert werden, führt aber zu einem übergeordneten Grid, das ein untergeordnetes Grid für jedes Element in der gebundenen Auflistung enthält. Dies ist eine sehr ineffiziente und problematische Verwendung des Grid-Layouts.

Auffüllen eines bindbaren Layouts mit Daten

Ein bindbares Layout wird mit Daten aufgefüllt, indem die Eigenschaft ItemsSource auf eine beliebige Auflistung festgelegt wird, die IEnumerable implementiert, und an eine Layout<T>-abgeleitete-Klasse angefügt wird:

<Grid BindableLayout.ItemsSource="{Binding Items}" />

Der entsprechende C#-Code lautet:

IEnumerable<string> items = ...;
var grid = new Grid();
BindableLayout.SetItemsSource(grid, items);

Wenn die angefügte Eigenschaft BindableLayout.ItemsSource für ein Layout festgelegt wird, aber die angefügte Eigenschaft BindableLayout.ItemTemplate nicht festgelegt ist, wird jedes Element in der IEnumerable-Sammlung durch eine Label angezeigt, die von der BindableLayout-Klasse erstellt wird.

Definieren der Darstellung des Elements

Die Darstellung der einzelnen Elemente im bindbaren Layout kann durch Festlegen der angefügten Eigenschaft BindableLayout.ItemTemplate auf eine DataTemplate definiert werden:

<StackLayout BindableLayout.ItemsSource="{Binding User.TopFollowers}"
             Orientation="Horizontal"
             ...>
    <BindableLayout.ItemTemplate>
        <DataTemplate>
            <controls:CircleImage Source="{Binding}"
                                  Aspect="AspectFill"
                                  WidthRequest="44"
                                  HeightRequest="44"
                                  ... />
        </DataTemplate>
    </BindableLayout.ItemTemplate>
</StackLayout>

Der entsprechende C#-Code lautet:

DataTemplate circleImageTemplate = ...;
var stackLayout = new StackLayout();
BindableLayout.SetItemsSource(stackLayout, viewModel.User.TopFollowers);
BindableLayout.SetItemTemplate(stackLayout, circleImageTemplate);

In diesem Beispiel wird jedes Element in der Auflistung von einer CircleImage in der TopFollowersDataTemplateFolgenden definierten Ansicht angezeigt:

Bindbares Layout mit einer DataTemplate

Weitere Informationen zu Datenvorlagen finden Sie unter Xamarin.Forms-Datenvorlagen.

Auswählen der Elementdarstellung zur Runtime

Die Darstellung jedes Elements im bindbaren Layout kann basierend auf dem Elementwert zur Runtime ausgewählt werden, indem die angefügte Eigenschaft BindableLayout.ItemTemplateSelector auf einen DataTemplateSelector festgelegt wird:

<FlexLayout BindableLayout.ItemsSource="{Binding User.FavoriteTech}"
            BindableLayout.ItemTemplateSelector="{StaticResource TechItemTemplateSelector}"
            ... />

Der entsprechende C#-Code lautet:

DataTemplateSelector dataTemplateSelector = new TechItemTemplateSelector { ... };
var flexLayout = new FlexLayout();
BindableLayout.SetItemsSource(flexLayout, viewModel.User.FavoriteTech);
BindableLayout.SetItemTemplateSelector(flexLayout, dataTemplateSelector);

Die DataTemplateSelector in der Beispielanwendung verwendete Anwendung wird im folgenden Beispiel gezeigt:

public class TechItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate DefaultTemplate { get; set; }
    public DataTemplate XamarinFormsTemplate { get; set; }

    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
    {
        return (string)item == "Xamarin.Forms" ? XamarinFormsTemplate : DefaultTemplate;
    }
}

Die TechItemTemplateSelector-Klasse definiert die Eigenschaften DefaultTemplate und XamarinFormsTemplateDataTemplate, die auf verschiedene Datenvorlagen festgelegt sind. Die OnSelectTemplate Methode gibt das XamarinFormsTemplateElement zurück, das ein Element dunkelrot mit einem Herzen daneben anzeigt, wenn das Element gleich "Xamarin.Forms" ist. Wenn das Element nicht gleich "Xamarin.Forms" ist, gibt die OnSelectTemplate Methode den DefaultTemplateWert zurück, der ein Element mit der Standardfarbe einer :Label

Bindbares Layout mit einem DataTemplateSelector

Weitere Informationen zu Datenvorlagenselektoren finden Sie unter Creating a Xamarin.Forms DataTemplateSelector.

Anzeigen einer Zeichenfolge, wenn Daten nicht verfügbar sind

Die Eigenschaft EmptyView kann auf eine Zeichenfolge festgelegt werden, die von einer Label angezeigt wird, wenn die ItemsSource-Eigenschaft null ist oder wenn die durch die Eigenschaft ItemsSource angegebene Sammlung null oder leer ist. Der folgende XAML-Code ist ein Beispiel für dieses Szenario:

<StackLayout BindableLayout.ItemsSource="{Binding UserWithoutAchievements.Achievements}"
             BindableLayout.EmptyView="No achievements">
    ...
</StackLayout>

Daraus ergibt sich, dass, wenn die datengebundene Auflistung null ist, die als EmptyView-Eigenschaftswert festgelegte Zeichenfolge angezeigt wird:

Screenshot einer gebundenen Layoutzeichenfolge, leere Ansicht, unter iOS und Android

Anzeigen von Ansichten bei nicht verfügbaren Daten

Die Eigenschaft EmptyView kann auf eine Ansicht festgelegt werden, die angezeigt wird, wenn die Eigenschaft ItemsSource den Wert null hat oder wenn die durch die Eigenschaft ItemsSource angegebene Sammlung null oder leer ist. Dies kann eine einzelne Ansicht oder eine Ansicht sein, die mehrere untergeordnete Ansichten enthält. Das folgende XAML-Beispiel zeigt die Eigenschaft EmptyView, die auf eine Ansicht festgelegt ist, die mehrere untergeordnete Ansichten enthält:

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

Das Ergebnis ist, dass, wenn die datengebundene Auflistung null ist, das StackLayout und dessen untergeordneten Elemente angezeigt werden.

Screenshot einer gebundenen Layout-leeren Ansicht mit mehreren Ansichten unter iOS und Android

Ebenso kann die EmptyViewTemplate auf ein DataTemplate festgelegt werden, das angezeigt wird, wenn die ItemsSource-Eigenschaft null ist, oder wenn die durch die ItemsSource-Eigenschaft angegebene Auflistung null oder leer ist. Das DataTemplate kann eine einzelne Ansicht oder eine Ansicht enthalten, die mehrere untergeordnete Ansichten enthält. Darüber hinaus wird der BindingContext des EmptyViewTemplate vom BindingContext des BindableLayout geerbt. Das folgende XAML-Beispiel zeigt den Eigenschaftensatz EmptyViewTemplate, der auf ein DataTemplate festgelegt ist, das eine einzelne Ansicht enthält:

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

Das Ergebnis ist, dass, wenn die datengebundene Auflistung null ist, das Label im DataTemplate angezeigt wird:

Screenshot einer leeren Ansichtsvorlage für ein bindbares Layout unter iOS und Android

Hinweis

Die Eigenschaft EmptyViewTemplate kann nicht über einen DataTemplateSelector festgelegt werden.

Auswählen von EmptyView zur Laufzeit

Ansichten, die als EmptyView angezeigt werden, wenn keine Daten verfügbar sind, können als ContentView-Objekte in ResourceDictionary definiert werden. Die Eigenschaft EmptyView kann dann zur Laufzeit basierend auf der Geschäftslogik auf eine bestimmte ContentView festgelegt werden. Der folgende XAML-Code ist ein Beispiel für dieses Szenario:

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

Der XAML-Code definiert zwei ContentView-Objekte auf der Seitenebene ResourceDictionary, wobei das Switch-Objekt steuert, welches ContentView-Objekt als EmptyView-Eigenschaftswert festgelegt wird. Wenn Switch umgeschaltet wird, führt der Ereignishandler OnEmptyViewSwitchToggled die Methode ToggleEmptyView aus:

void ToggleEmptyView(bool isToggled)
{
    object view = isToggled ? Resources["BasicEmptyView"] : Resources["AdvancedEmptyView"];
    BindableLayout.SetEmptyView(stackLayout, view);
}

Die ToggleEmptyView-Methode legt die EmptyView-Eigenschaft des stackLayout-Objekts auf der Grundlage des Wertes der Switch.IsToggled-Eigenschaft auf eines der beiden ContentView-Objekte fest, die im ResourceDictionary gespeichert sind. Wenn dann die datengebundene Auflistung ist null, wird das ContentView als EmptyView Eigenschaft festgelegte Objekt angezeigt:

Screenshot der auswahl leeren Ansicht zur Laufzeit unter iOS und Android