Xamarin.Forms Visual State Manager

Beispiel herunterladen Das Beispiel herunterladen

Verwenden Sie den Visual State Manager, um Änderungen an XAML-Elementen basierend auf visuellen Zuständen vorzunehmen, die aus Code festgelegt werden.

Visual State Manager (VSM) bietet eine strukturierte Möglichkeit, visuelle Änderungen an der Benutzeroberfläche aus Code vorzunehmen. In den meisten Fällen ist die Benutzeroberfläche der Anwendung in XAML definiert, und dieser XAML-Code enthält Markup, das beschreibt, wie sich der Visual State Manager auf die Visuals der Benutzeroberfläche auswirkt.

Das VSM führt das Konzept der visuellen Zustände ein. Eine Xamarin.Forms Ansicht wie ein Button kann je nach zugrunde liegendem Zustand mehrere unterschiedliche visuelle Darstellungen aufweisen – unabhängig davon, ob sie deaktiviert oder gedrückt ist oder den Eingabefokus hat. Dies sind die Zustände der Schaltfläche.

Visuelle Zustände werden in visuellen Zustandsgruppen gesammelt. Alle visuellen Zustände innerhalb einer visuellen Zustandsgruppe schließen sich gegenseitig aus. Sowohl visuelle Zustände als auch visuelle Zustandsgruppen werden durch einfache Textzeichenfolgen identifiziert.

Der Xamarin.Forms Visual State Manager definiert eine visuelle Zustandsgruppe namens "CommonStates" mit den folgenden visuellen Zuständen:

  • "Normal"
  • "Deaktiviert"
  • "Fokussiert"
  • "Ausgewählt"

Diese visuelle Zustandsgruppe wird für alle Klassen unterstützt, die von VisualElementabgeleitet werden. Dies ist die Basisklasse für View und Page.

Sie können auch eigene visuelle Zustandsgruppen und visuelle Zustände definieren, wie in diesem Artikel veranschaulicht wird.

Hinweis

Xamarin.Forms Entwickler, die mit Triggern vertraut sind, wissen, dass Trigger auch Änderungen an Visuals in der Benutzeroberfläche vornehmen können, basierend auf Änderungen in den Eigenschaften einer Ansicht oder dem Auslösen von Ereignissen. Die Verwendung von Triggern für verschiedene Kombinationen dieser Änderungen kann jedoch ziemlich verwirrend werden. In der Vergangenheit wurde der Visual State Manager in Windows XAML-basierten Umgebungen eingeführt, um die Verwirrung zu verringern, die sich aus Kombinationen von visuellen Zuständen ergibt. Mit dem VSM schließen sich die visuellen Zustände innerhalb einer visuellen Zustandsgruppe immer gegenseitig aus. Zu jedem Zeitpunkt ist nur ein Zustand in jeder Gruppe der aktuelle Zustand.

Allgemeine Zustände

Mit dem Visual State Manager können Sie Markup in Ihre XAML-Datei einfügen, das das visuelle Erscheinungsbild einer Ansicht ändern kann, wenn die Ansicht normal oder deaktiviert ist oder den Eingabefokus hat. Diese werden als allgemeine Zustände bezeichnet.

Angenommen, Sie verfügen über eine Entry Ansicht auf Ihrer Seite, und Sie möchten, dass sich die visuelle Darstellung von Entry auf folgende Weise ändert:

  • Die Entry sollte einen rosa Hintergrund haben, wenn deaktiviert Entry ist.
  • Die Entry sollte normalerweise einen Kalkhintergrund haben.
  • Der Entry sollte auf das Doppelte seiner normalen Höhe erweitert werden, wenn es den Eingabefokus hat.

Sie können das VSM-Markup an eine einzelne Ansicht anfügen oder in einem Stil definieren, wenn es für mehrere Ansichten gilt. In den nächsten beiden Abschnitten werden diese Ansätze beschrieben.

VSM-Markup für eine Ansicht

Wenn Sie VSM-Markup an eine Entry Ansicht anfügen möchten, trennen Sie zuerst in Entry Start- und Endtags:

<Entry FontSize="18">

</Entry>

Es erhält einen expliziten Schriftgrad, da einer der Zustände die FontSize -Eigenschaft verwendet, um die Größe des Texts im Entryzu verdoppeln.

Fügen Sie als Nächstes Tags zwischen diesen Tags ein VisualStateManager.VisualStateGroups :

<Entry FontSize="18">
    <VisualStateManager.VisualStateGroups>

    </VisualStateManager.VisualStateGroups>
</Entry>

VisualStateGroups ist eine angefügte bindbare Eigenschaft, die von der VisualStateManager -Klasse definiert wird. (Weitere Informationen zu angefügten bindbaren Eigenschaften finden Sie im Artikel Angefügte Eigenschaften.) So wird die VisualStateGroups -Eigenschaft an das Entry -Objekt angefügt.

Die VisualStateGroups -Eigenschaft ist vom Typ VisualStateGroupList, die eine Auflistung von VisualStateGroup -Objekten ist. Fügen Sie innerhalb der VisualStateManager.VisualStateGroups Tags ein Paar von VisualStateGroup Tags für jede Gruppe von visuellen Zuständen ein, die Sie einschließen möchten:

<Entry FontSize="18">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">

        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Entry>

Beachten Sie, dass das VisualStateGroup Tag über ein x:Name Attribut verfügt, das den Namen der Gruppe angibt. Die VisualStateGroup -Klasse definiert eine Name Eigenschaft, die Sie stattdessen verwenden können:

<VisualStateGroup Name="CommonStates">

Sie können entweder x:Name oder Name , aber nicht beides im selben Element verwenden.

Die VisualStateGroup -Klasse definiert eine Eigenschaft mit dem Namen States, bei der es sich um eine Auflistung von VisualState -Objekten handelt. States ist die content-Eigenschaft von, VisualStateGroups sodass Sie die VisualState Tags direkt zwischen den VisualStateGroup Tags einschließen können. (Inhaltseigenschaften werden im Artikel Grundlegende XAML-Syntax erläutert.)

Der nächste Schritt besteht darin, ein Paar von Tags für jeden visuellen Zustand in dieser Gruppe einzuschließen. Diese können auch mit x:Name oder Nameidentifiziert werden:

<Entry FontSize="18">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">
            <VisualState x:Name="Normal">

            </VisualState>

            <VisualState x:Name="Focused">

            </VisualState>

            <VisualState x:Name="Disabled">

            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Entry>

VisualState definiert eine Eigenschaft mit dem Namen Setters, bei der es sich um eine Auflistung von Setter -Objekten handelt. Dies sind die gleichen Setter Objekte, die Sie in einem Style -Objekt verwenden.

Setters ist nicht die content-Eigenschaft von VisualState, daher ist es erforderlich, Eigenschaftselementtags für die Setters -Eigenschaft einzuschließen:

<Entry FontSize="18">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">
            <VisualState x:Name="Normal">
                <VisualState.Setters>

                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="Focused">
                <VisualState.Setters>

                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="Disabled">
                <VisualState.Setters>

                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Entry>

Sie können jetzt ein oder Setter mehrere Objekte zwischen jedem Tagpaar Setters einfügen. Dies sind die Setter Objekte, die die zuvor beschriebenen visuellen Zustände definieren:

<Entry FontSize="18">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">
            <VisualState x:Name="Normal">
                <VisualState.Setters>
                    <Setter Property="BackgroundColor" Value="Lime" />
                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="Focused">
                <VisualState.Setters>
                    <Setter Property="FontSize" Value="36" />
                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="Disabled">
                <VisualState.Setters>
                    <Setter Property="BackgroundColor" Value="Pink" />
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Entry>

Jedes Setter Tag gibt den Wert einer bestimmten Eigenschaft an, wenn dieser Zustand aktuell ist. Jede Eigenschaft, auf die von einem Setter -Objekt verwiesen wird, muss durch eine bindbare Eigenschaft gesichert werden.

Markup ähnlich wie dieses ist die Grundlage der VsM on View-Seite im VsmDemos-Beispielprogramm . Die Seite enthält drei Entry Ansichten, aber nur in der zweiten ist das VSM-Markup angefügt:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:VsmDemos"
             x:Class="VsmDemos.MainPage"
             Title="VSM Demos">

    <StackLayout>
        <StackLayout.Resources>
            <Style TargetType="Entry">
                <Setter Property="Margin" Value="20, 0" />
                <Setter Property="FontSize" Value="18" />
            </Style>

            <Style TargetType="Label">
                <Setter Property="Margin" Value="20, 30, 20, 0" />
                <Setter Property="FontSize" Value="Large" />
            </Style>
        </StackLayout.Resources>

        <Label Text="Normal Entry:" />
        <Entry />
        <Label Text="Entry with VSM: " />
        <Entry>
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup x:Name="CommonStates">
                    <VisualState x:Name="Normal">
                        <VisualState.Setters>
                            <Setter Property="BackgroundColor" Value="Lime" />
                        </VisualState.Setters>
                    </VisualState>
                    <VisualState x:Name="Focused">
                        <VisualState.Setters>
                            <Setter Property="FontSize" Value="36" />
                        </VisualState.Setters>
                    </VisualState>
                    <VisualState x:Name="Disabled">
                        <VisualState.Setters>
                            <Setter Property="BackgroundColor" Value="Pink" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>

            <Entry.Triggers>
                <DataTrigger TargetType="Entry"
                             Binding="{Binding Source={x:Reference entry3},
                                               Path=Text.Length}"
                             Value="0">
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
            </Entry.Triggers>
        </Entry>
        <Label Text="Entry to enable 2nd Entry:" />
        <Entry x:Name="entry3"
               Text=""
               Placeholder="Type something to enable 2nd Entry" />
    </StackLayout>
</ContentPage>

Beachten Sie, dass die zweite Entry auch einen DataTrigger als Teil der Trigger Auflistung enthält. Dies führt dazu, dass deaktiviert Entry wird, bis etwas in die dritte Entryeingegeben wird. Dies ist die Seite beim Start unter iOS, Android und dem Universelle Windows-Plattform (UWP):

VSM in Der Ansicht: VsM

Der aktuelle visuelle Zustand ist "Deaktiviert", sodass der Hintergrund des zweiten Entry auf den iOS- und Android-Bildschirmen rosa ist. Die UWP-Implementierung von Entry lässt das Festlegen der Hintergrundfarbe nicht zu, wenn deaktiviert Entry ist.

Wenn Sie Text in die dritte Entryeingeben, wechselt der zweite Entry in den Zustand "Normal", und der Hintergrund ist nun lime:

VSM on View: Normal

Wenn Sie den zweiten Entryberühren, erhält er den Eingabefokus. Er wechselt in den Status "Fokussiert" und wird auf die doppelte Höhe erweitert:

VSM on View:

Beachten Sie, dass der Entry Kalkhintergrund nicht beibehalten wird, wenn der Eingabefokus abgerufen wird. Wenn der Visual State Manager zwischen den visuellen Zuständen wechselt, sind die vom vorherigen Zustand festgelegten Eigenschaften nicht festgelegt. Beachten Sie, dass sich die visuellen Zustände gegenseitig ausschließen. Der Status "Normal" bedeutet nicht nur, dass aktiviert Entry ist. Dies bedeutet, dass aktiviert Entry ist und keinen Eingabefokus hat.

Wenn sie einen Entry Kalkhintergrund im Status "Fokussiert" haben soll, fügen Sie diesem visuellen Zustand eine weitere Setter hinzu:

<VisualState x:Name="Focused">
    <VisualState.Setters>
        <Setter Property="FontSize" Value="36" />
        <Setter Property="BackgroundColor" Value="Lime" />
    </VisualState.Setters>
</VisualState>

Damit diese Setter Objekte ordnungsgemäß funktionieren, muss ein VisualStateGroup -Objekt Objekte für alle Zustände in dieser Gruppe enthalten VisualState . Wenn ein visueller Zustand ohne Setter Objekte vorhanden ist, schließen Sie ihn trotzdem als leeres Tag ein:

<VisualState x:Name="Normal" />

Visual State Manager-Markup in einem Stil

Es ist häufig erforderlich, dasselbe Visual State Manager-Markup für zwei oder mehr Ansichten gemeinsam zu verwenden. In diesem Fall sollten Sie das Markup in eine Style Definition einfügen.

Dies ist die vorhandene implizite Style für die Entry Elemente auf der VsM On View-Seite :

<Style TargetType="Entry">
    <Setter Property="Margin" Value="20, 0" />
    <Setter Property="FontSize" Value="18" />
</Style>

Fügen Sie Setter Tags für die VisualStateManager.VisualStateGroups angefügte bindbare Eigenschaft hinzu:

<Style TargetType="Entry">
    <Setter Property="Margin" Value="20, 0" />
    <Setter Property="FontSize" Value="18" />
    <Setter Property="VisualStateManager.VisualStateGroups">

    </Setter>
</Style>

Die Inhaltseigenschaft für Setter ist Value, sodass der Wert der Value Eigenschaft direkt innerhalb dieser Tags angegeben werden kann. Diese Eigenschaft ist vom Typ VisualStateGroupList:

<Style TargetType="Entry">
    <Setter Property="Margin" Value="20, 0" />
    <Setter Property="FontSize" Value="18" />
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>

        </VisualStateGroupList>
    </Setter>
</Style>

Innerhalb dieser Tags können Sie eines von mehreren VisualStateGroup Objekten einschließen:

<Style TargetType="Entry">
    <Setter Property="Margin" Value="20, 0" />
    <Setter Property="FontSize" Value="18" />
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>
            <VisualStateGroup x:Name="CommonStates">

            </VisualStateGroup>
        </VisualStateGroupList>
    </Setter>
</Style>

Der Rest des VSM-Markups ist derselbe wie zuvor.

Hier sehen Sie die Seite VSM in Style mit dem vollständigen VSM-Markup:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="VsmDemos.VsmInStylePage"
             Title="VSM in Style">
    <StackLayout>
        <StackLayout.Resources>
            <Style TargetType="Entry">
                <Setter Property="Margin" Value="20, 0" />
                <Setter Property="FontSize" Value="18" />
                <Setter Property="VisualStateManager.VisualStateGroups">
                    <VisualStateGroupList>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="Lime" />
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="Focused">
                                <VisualState.Setters>
                                    <Setter Property="FontSize" Value="36" />
                                    <Setter Property="BackgroundColor" Value="Lime" />
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="Disabled">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="Pink" />
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateGroupList>
                </Setter>
            </Style>

            <Style TargetType="Label">
                <Setter Property="Margin" Value="20, 30, 20, 0" />
                <Setter Property="FontSize" Value="Large" />
            </Style>
        </StackLayout.Resources>

        <Label Text="Normal Entry:" />
        <Entry />
        <Label Text="Entry with VSM: " />
        <Entry>
            <Entry.Triggers>
                <DataTrigger TargetType="Entry"
                             Binding="{Binding Source={x:Reference entry3},
                                               Path=Text.Length}"
                             Value="0">
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
            </Entry.Triggers>
        </Entry>
        <Label Text="Entry to enable 2nd Entry:" />
        <Entry x:Name="entry3"
               Text=""
               Placeholder="Type something to enable 2nd Entry" />
    </StackLayout>
</ContentPage>

Jetzt reagieren alle Entry Ansichten auf dieser Seite auf die gleiche Weise auf ihre visuellen Zustände. Beachten Sie auch, dass der Status "Fokussiert" jetzt eine Sekunde Setter enthält, die jedem Entry einen Kalkhintergrund gibt, auch wenn er den Eingabefokus hat:

VSM in Style

Visuelle Zustände in Xamarin.Forms

In der folgenden Tabelle sind die visuellen Zustände aufgeführt, die in Xamarin.Formsdefiniert sind:

Klasse Zustände Weitere Informationen
Button Pressed Visuelle Schaltflächenzustände
CheckBox IsChecked Visuelle CheckBox-Zustände
CarouselView DefaultItem, CurrentItem, PreviousItem, NextItem CarouselView-Visuelle Zustände
ImageButton Pressed Visuelle ImageButton-Zustände
RadioButton Checked, Unchecked Visuelle RadioButton-Zustände
Switch On, Off Wechseln von visuellen Zuständen
VisualElement Normal, Disabled, Focused, Selected Allgemeine Zustände

Auf jeden dieser Zustände kann über die visuelle Zustandsgruppe namens CommonStateszugegriffen werden.

Darüber hinaus implementiert der CollectionView - Selected Zustand. Weitere Informationen finden Sie unter Ändern der farbe des ausgewählten Elements.

Festlegen des Zustands für mehrere Elemente

In den vorherigen Beispielen wurden visuelle Zustände an einzelne Elemente angefügt und darauf ausgeführt. Es ist jedoch auch möglich, visuelle Zustände zu erstellen, die an ein einzelnes Element angefügt sind, aber Eigenschaften für andere Elemente innerhalb desselben Bereichs festlegen. Dadurch wird vermieden, dass visuelle Zustände für jedes Element wiederholt werden müssen, auf dem die Zustände ausgeführt werden.

Der Setter Typ verfügt über eine TargetName -Eigenschaft vom Typ string, die das Zielelement darstellt, das von Setter für einen visuellen Zustand bearbeitet wird. Wenn die TargetName -Eigenschaft definiert ist, legt die Setter des Property in TargetName definierten Elements auf fest Value:

<Setter TargetName="label"
        Property="Label.TextColor"
        Value="Red" />

In diesem Beispiel ist die -Eigenschaft eines Label benannten labelTextColor auf Redfestgelegt. Beim Festlegen der TargetName -Eigenschaft müssen Sie den vollständigen Pfad zur -Eigenschaft in Propertyangeben. Daher wird zum Festlegen der TextColor -Eigenschaft auf einem PropertyLabelals Label.TextColorangegeben.

Hinweis

Jede Eigenschaft, auf die von einem Setter -Objekt verwiesen wird, muss durch eine bindbare Eigenschaft gesichert werden.

Auf der Seite VSM mit Setter TargetName im VsmDemos-Beispiel wird gezeigt, wie der Zustand für mehrere Elemente aus einer einzelnen visuellen Zustandsgruppe festgelegt wird. Die XAML-Datei besteht aus einem StackLayout , das ein Label -Element enthält, eine Entry- und eine Button- :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="VsmDemos.VsmSetterTargetNamePage"
             Title="VSM with Setter TargetName">
    <StackLayout Margin="10">
        <Label Text="What is the capital of France?" />
        <Entry x:Name="entry"
               Placeholder="Enter answer" />
        <Button Text="Reveal answer">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup x:Name="CommonStates">
                    <VisualState x:Name="Normal" />
                    <VisualState x:Name="Pressed">
                        <VisualState.Setters>
                            <Setter Property="Scale"
                                    Value="0.8" />
                            <Setter TargetName="entry"
                                    Property="Entry.Text"
                                    Value="Paris" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </Button>
    </StackLayout>
</ContentPage>

VSM-Markup ist an StackLayoutangefügt. Es gibt zwei sich gegenseitig ausschließende Zustände mit den Namen "Normal" und "Pressed", wobei jeder Zustand Tags enthält VisualState .

Der Status "Normal" ist aktiv, wenn nicht Button gedrückt wird, und eine Antwort auf die Frage kann eingegeben werden:

VSM Setter TargetName: Normal State

Der Zustand "Gedrückt" wird aktiv, wenn gedrückt Button wird:

VSM Setter TargetName: Drücken des

"Pressed" VisualState gibt an, dass die Button -Eigenschaft beim Drücken Scale von vom Standardwert 1 in 0,8 geändert wird. Darüber hinaus ist Text für die Entry benannte entry Eigenschaft Paris festgelegt. Daher ist das Ergebnis, dass, wenn gedrückt Button wird, es auf etwas kleiner skaliert wird, und die Entry Anzeige Paris. Wenn der Button dann freigegeben wird, wird es auf den Standardwert 1 skaliert, und der Entry zeigt alle zuvor eingegebenen Text an.

Wichtig

Eigenschaftenpfade werden in Elementen, die die TargetName -Eigenschaft angeben, derzeit nicht unterstütztSetter.

Definieren Eigener visueller Zustände

Jede Klasse, die von VisualElement abgeleitet wird, unterstützt die allgemeinen Zustände "Normal", "Focused" und "Disabled". Darüber hinaus unterstützt die CollectionView -Klasse den Status "Ausgewählt". Intern erkennt die VisualElement Klasse, wenn sie aktiviert oder deaktiviert wird, oder wenn sie fokussiert oder nicht fokussiert wird, und ruft die statische VisualStateManager.GoToState Methode auf:

VisualStateManager.GoToState(this, "Focused");

Dies ist der einzige Visual State Manager-Code, den Sie in der VisualElement -Klasse finden. Da GoToState für jedes Objekt aufgerufen wird, basierend auf jeder Klasse, die von VisualElementabgeleitet wird, können Sie den Visual State Manager mit jedem VisualElement -Objekt verwenden, um auf diese Änderungen zu reagieren.

Interessanterweise wird in VisualElementnicht explizit auf den Namen der visuellen Zustandsgruppe "CommonStates" verwiesen. Der Gruppenname ist nicht Teil der API für den Visual State Manager. Innerhalb eines der beiden bisher gezeigten Beispielprogramme können Sie den Namen der Gruppe von "CommonStates" in alles andere ändern, und das Programm funktioniert weiterhin. Der Gruppenname ist lediglich eine allgemeine Beschreibung der Zustände in dieser Gruppe. Es wird implizit verstanden, dass sich die visuellen Zustände in einer Gruppe gegenseitig ausschließen: Ein Zustand und nur ein Zustand ist zu einem beliebigen Zeitpunkt aktuell.

Wenn Sie Ihre eigenen visuellen Zustände implementieren möchten, müssen Sie aus Code aufrufen VisualStateManager.GoToState . In den meisten Fällen führen Sie diesen Aufruf aus der CodeBehind-Datei Ihrer Seitenklasse aus.

Auf der Seite VSM-Validierung im VsmDemos-Beispiel wird gezeigt, wie Sie den Visual State Manager in Verbindung mit der Eingabeüberprüfung verwenden. Die XAML-Datei besteht aus einem StackLayout , das zwei Label Elemente enthält: Entryund Button:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="VsmDemos.VsmValidationPage"
             Title="VSM Validation">
    <StackLayout x:Name="stackLayout"
                 Padding="10, 10">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup Name="ValidityStates">
                    <VisualState Name="Valid">
                        <VisualState.Setters>
                            <Setter TargetName="helpLabel"
                                    Property="Label.TextColor"
                                    Value="Transparent" />
                            <Setter TargetName="entry"
                                    Property="Entry.BackgroundColor"
                                    Value="Lime" />
                        </VisualState.Setters>
                    </VisualState>
                    <VisualState Name="Invalid">
                        <VisualState.Setters>
                            <Setter TargetName="entry"
                                    Property="Entry.BackgroundColor"
                                    Value="Pink" />
                            <Setter TargetName="submitButton"
                                    Property="Button.IsEnabled"
                                    Value="False" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        <Label Text="Enter a U.S. phone number:"
               FontSize="Large" />
        <Entry x:Name="entry"
               Placeholder="555-555-5555"
               FontSize="Large"
               Margin="30, 0, 0, 0"
               TextChanged="OnTextChanged" />
        <Label x:Name="helpLabel"
               Text="Phone number must be of the form 555-555-5555, and not begin with a 0 or 1" />
        <Button x:Name="submitButton"
                Text="Submit"
                FontSize="Large"
                Margin="0, 20"
                VerticalOptions="Center"
                HorizontalOptions="Center" />
    </StackLayout>
</ContentPage>

VSM-Markup wird an die StackLayout angefügt (mit dem Namen stackLayout). Es gibt zwei sich gegenseitig ausschließende Zustände mit dem Namen "Gültig" und "Ungültig", wobei jeder Zustand Tags enthält VisualState .

Wenn die Entry keine gültige Telefonnummer enthält, lautet der aktuelle Status "Ungültig", und daher hat die Entry einen rosa Hintergrund, die zweite Label ist sichtbar, und die Button ist deaktiviert:

VSM-Validierung: Ungültiger Zustand

Wenn eine gültige Telefonnummer eingegeben wird, lautet der aktuelle Status "Gültig". Ruft Entry einen kalkfarbenen Hintergrund ab, der zweite Label verschwindet, und der Button ist jetzt aktiviert:

VSM-Validierung:

Die CodeBehind-Datei ist für die Behandlung des TextChanged -Ereignisses aus dem Entryverantwortlich. Der Handler verwendet einen regulären Ausdruck, um zu bestimmen, ob die Eingabezeichenfolge gültig ist. Die -Methode in der CodeBehind-Datei namens GoToState ruft die statische VisualStateManager.GoToState Methode für stackLayoutauf:

public partial class VsmValidationPage : ContentPage
{
    public VsmValidationPage()
    {
        InitializeComponent();

        GoToState(false);
    }

    void OnTextChanged(object sender, TextChangedEventArgs args)
    {
        bool isValid = Regex.IsMatch(args.NewTextValue, @"^[2-9]\d{2}-\d{3}-\d{4}$");
        GoToState(isValid);
    }

    void GoToState(bool isValid)
    {
        string visualState = isValid ? "Valid" : "Invalid";
        VisualStateManager.GoToState(stackLayout, visualState);
    }
}

Beachten Sie auch, dass die GoToState -Methode vom Konstruktor aufgerufen wird, um den Zustand zu initialisieren. Es sollte immer ein aktueller Zustand vorhanden sein. Aber nirgends im Code gibt es einen Verweis auf den Namen der visuellen Zustandsgruppe, obwohl er im XAML aus Gründen der Übersichtlichkeit als "ValidationStates" referenziert wird.

Beachten Sie, dass die CodeBehind-Datei nur das -Objekt auf der Seite berücksichtigen muss, die die visuellen Zustände definiert, und für dieses Objekt aufrufen VisualStateManager.GoToState muss. Dies liegt daran, dass beide visuellen Zustände auf mehrere Objekte auf der Seite ausgerichtet sind.

Sie fragen sich vielleicht: Wenn die CodeBehind-Datei auf das Objekt auf der Seite verweisen muss, die die visuellen Zustände definiert, warum kann die CodeBehind-Datei nicht einfach direkt auf diese und andere Objekte zugreifen? Das könnte es sicherlich. Der Vorteil der Verwendung von VSM besteht jedoch darin, dass Sie steuern können, wie visuelle Elemente vollständig in XAML auf unterschiedliche Status reagieren, wodurch der gesamte UI-Entwurf an einem Ort bleibt. Dadurch wird vermieden, dass das visuelle Erscheinungsbild festgelegt wird, indem auf visuelle Elemente direkt vom CodeBehind aus zugegriffen wird.

Visuelle Zustandstrigger

Visuelle Zustände unterstützen Zustandstrigger, bei denen es sich um eine spezielle Gruppe von Triggern handelt, die die Bedingungen definieren, unter denen ein VisualState angewendet werden soll.

Zustandstrigger werden der Sammlung StateTriggers eines VisualState hinzugefügt. Diese Sammlung kann Trigger mit einem oder mehreren Zustandstriggern enthalten. Ein VisualState wird angewendet, wenn alle Zustandstrigger in der Sammlung aktiv sind.

Bei Verwendung von Zustandstriggern zur Steuerung visueller Zustände befolgt Xamarin.Forms die folgenden Prioritätsregeln, um zu bestimmen, welcher Trigger (und welches entsprechende VisualState-Element) aktiv ist:

  1. Alle von StateTriggerBase abgeleiteten Trigger.
  2. Ein AdaptiveTrigger, der aktiviert wird, da die Bedingung MinWindowWidth erfüllt ist.
  3. Ein AdaptiveTrigger, der aktiviert wird, da die Bedingung MinWindowHeight erfüllt ist.

Wenn mehrere Trigger gleichzeitig aktiv sind (z. B. zwei benutzerdefinierte Trigger), hat der erste im Markup deklarierte Trigger Vorrang.

Weitere Informationen zu Zustandstriggern finden Sie unter Zustandstrigger.

Verwenden des Visual State Managers für adaptives Layout

Eine Xamarin.Forms anwendung, die auf einem Smartphone ausgeführt wird, kann in der Regel im Seitenverhältnis im Hoch- oder Querformat angezeigt werden, und ein Xamarin.Forms programm, das auf dem Desktop ausgeführt wird, kann so angepasst werden, dass es viele verschiedene Größen und Seitenverhältnisse annimmt. Eine gut entworfene Anwendung kann ihren Inhalt für diese verschiedenen Seiten- oder Fensterformfaktoren unterschiedlich anzeigen.

Diese Technik wird manchmal auch als adaptives Layout bezeichnet. Da adaptives Layout ausschließlich die Visuals eines Programms umfasst, ist es eine ideale Anwendung des Visual State Managers.

Ein einfaches Beispiel ist eine Anwendung, die eine kleine Sammlung von Schaltflächen anzeigt, die sich auf den Inhalt der Anwendung auswirken. Im Hochformatmodus werden diese Schaltflächen möglicherweise in einer horizontalen Zeile oben auf der Seite angezeigt:

VSM Adaptive Layout: Adaptives

Im Querformatmodus kann das Array von Schaltflächen auf eine Seite verschoben und in einer Spalte angezeigt werden:

ADAPTIVEs VSM-Layout: Adaptives

Von oben nach unten wird das Programm unter den Universelle Windows-Plattform, Android und iOS ausgeführt.

Die VsM Adaptive Layout-Seite im VsmDemos-Beispiel definiert eine Gruppe mit dem Namen "OrientationStates" mit den beiden visuellen Zuständen "Hochformat" und "Querformat". (Ein komplexerer Ansatz kann auf verschiedenen Seiten- oder Fensterbreiten basieren.)

VSM-Markup tritt an vier Stellen in der XAML-Datei auf. Die StackLayout benannte mainStack enthält sowohl das Menü als auch den Inhalt, bei dem es sich um ein Image Element handelt. Dies StackLayout sollte eine vertikale Ausrichtung im Hochformat und eine horizontale Ausrichtung im Querformat aufweisen:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="VsmDemos.VsmAdaptiveLayoutPage"
             Title="VSM Adaptive Layout">

    <StackLayout x:Name="mainStack">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup Name="OrientationStates">
                <VisualState Name="Portrait">
                    <VisualState.Setters>
                        <Setter Property="Orientation" Value="Vertical" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState Name="Landscape">
                    <VisualState.Setters>
                        <Setter Property="Orientation" Value="Horizontal" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <ScrollView x:Name="menuScroll">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup Name="OrientationStates">
                    <VisualState Name="Portrait">
                        <VisualState.Setters>
                            <Setter Property="Orientation" Value="Horizontal" />
                        </VisualState.Setters>
                    </VisualState>
                    <VisualState Name="Landscape">
                        <VisualState.Setters>
                            <Setter Property="Orientation" Value="Vertical" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>

            <StackLayout x:Name="menuStack">
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup Name="OrientationStates">
                        <VisualState Name="Portrait">
                            <VisualState.Setters>
                                <Setter Property="Orientation" Value="Horizontal" />
                            </VisualState.Setters>
                        </VisualState>
                        <VisualState Name="Landscape">
                            <VisualState.Setters>
                                <Setter Property="Orientation" Value="Vertical" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>

                <StackLayout.Resources>
                    <Style TargetType="Button">
                        <Setter Property="VisualStateManager.VisualStateGroups">
                            <VisualStateGroupList>
                                <VisualStateGroup Name="OrientationStates">
                                    <VisualState Name="Portrait">
                                        <VisualState.Setters>
                                            <Setter Property="HorizontalOptions" Value="CenterAndExpand" />
                                            <Setter Property="Margin" Value="10, 5" />
                                        </VisualState.Setters>
                                    </VisualState>
                                    <VisualState Name="Landscape">
                                        <VisualState.Setters>
                                            <Setter Property="VerticalOptions" Value="CenterAndExpand" />
                                            <Setter Property="HorizontalOptions" Value="Center" />
                                            <Setter Property="Margin" Value="10" />
                                        </VisualState.Setters>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateGroupList>
                        </Setter>
                    </Style>
                </StackLayout.Resources>

                <Button Text="Banana"
                        Command="{Binding SelectedCommand}"
                        CommandParameter="Banana.jpg" />
                <Button Text="Face Palm"
                        Command="{Binding SelectedCommand}"
                        CommandParameter="FacePalm.jpg" />
                <Button Text="Monkey"
                        Command="{Binding SelectedCommand}"
                        CommandParameter="monkey.png" />
                <Button Text="Seated Monkey"
                        Command="{Binding SelectedCommand}"
                        CommandParameter="SeatedMonkey.jpg" />
            </StackLayout>
        </ScrollView>

        <Image x:Name="image"
               VerticalOptions="FillAndExpand"
               HorizontalOptions="FillAndExpand" />
    </StackLayout>
</ContentPage>

Das innere ScrollView und menuScroll das StackLayout benannte menuStack implementieren das Menü von Schaltflächen. Die Ausrichtung dieser Layouts ist entgegengesetzt von mainStack. Das Menü sollte im Hochformat horizontal und im Querformat vertikal sein.

Der vierte Abschnitt des VSM-Markups ist implizit für die Schaltflächen selbst. Dieses Markup legt VerticalOptionseigenschaften , HorizontalOptionsund fest, die Margin speziell für die Ausrichtungen im Hoch- und Querformat gelten.

Die CodeBehind-Datei legt die BindingContext -Eigenschaft von menuStack fest, um Befehle zu implementieren Button , und fügt auch einen Handler an das SizeChanged Ereignis der Seite an:

public partial class VsmAdaptiveLayoutPage : ContentPage
{
    public VsmAdaptiveLayoutPage ()
    {
        InitializeComponent ();

        SizeChanged += (sender, args) =>
        {
            string visualState = Width > Height ? "Landscape" : "Portrait";
            VisualStateManager.GoToState(mainStack, visualState);
            VisualStateManager.GoToState(menuScroll, visualState);
            VisualStateManager.GoToState(menuStack, visualState);

            foreach (View child in menuStack.Children)
            {
                VisualStateManager.GoToState(child, visualState);
            }
        };

        SelectedCommand = new Command<string>((filename) =>
        {
            image.Source = ImageSource.FromResource("VsmDemos.Images." + filename);
        });

        menuStack.BindingContext = this;
    }

    public ICommand SelectedCommand { private set; get; }
}

Der SizeChanged Handler ruft VisualStateManager.GoToState für die beiden StackLayout Elemente und auf ScrollView und durchläuft dann die untergeordneten Elemente vonmenuStack, um für die Button -Elemente aufzurufenVisualStateManager.GoToState.

Es mag so aussehen, als ob die CodeBehind-Datei Ausrichtungsänderungen direkter behandeln kann, indem Eigenschaften von Elementen in der XAML-Datei festgelegt werden, aber der Visual State Manager ist definitiv ein strukturierter Ansatz. Alle Visuals werden in der XAML-Datei gespeichert, wo sie einfacher zu untersuchen, zu verwalten und zu ändern sind.

Visual State Manager mit Xamarin.University

Xamarin.Forms Video zu Visual State Manager 3.0