Freigeben über


Xamarin.Forms Visual State Manager

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

Der Visual State Manager (VSM) bietet eine strukturierte Möglichkeit, visuelle Änderungen an der Benutzeroberfläche über Code vorzunehmen. In den meisten Fällen wird 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 visuellen Elemente der Benutzeroberfläche auswirkt.

Das VSM führt das Konzept visueller Zustände ein. Eine Xamarin.Forms Ansicht, z. B. eine Button Ansicht, 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 Status der Schaltfläche.

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

Der Xamarin.Forms Visual State-Manager definiert eine Gruppe visueller Zustände namens "CommonStates" mit den folgenden visuellen Zuständen:

  • "Normal"
  • "Disabled"
  • "Relevant"
  • "Ausgewählt"

Diese Gruppe visueller Zustände wird für alle Klassen unterstützt, die von VisualElementder Basisklasse abgeleitet sind, 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 visuellen Elementen auf der Benutzeroberfläche vornehmen können, basierend auf Änderungen in den Eigenschaften einer Ansicht oder dem Auslösen von Ereignissen. Die Verwendung von Triggern zur Behandlung verschiedener Kombinationen dieser Änderungen kann jedoch ziemlich verwirrend werden. Historisch wurde der Visual State Manager in Windows XAML-basierten Umgebungen eingeführt, um die Verwirrung zu verringern, die sich aus Kombinationen visueller Zustände ergibt. Mit dem VSM schließen sich die visuellen Zustände innerhalb einer Gruppe visueller Zustände immer gegenseitig aus. Zu jedem Zeitpunkt ist nur ein Zustand in jeder Gruppe der aktuelle Zustand.

Allgemeine Status

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

Angenommen, Sie haben eine Entry-Ansicht auf Ihrer Seite und möchten, dass sich das visuelle Erscheinungsbild der Entry-Ansicht auf folgende Weise ändert:

  • Entry sollte einen rosa Hintergrund haben, wenn der Entry deaktiviert ist.
  • Entry sollte normalerweise einen kalkfarbenen Hintergrund haben.
  • Entry sollte sich auf das Doppelte seiner normalen Höhe ausdehnen, wenn er den Eingabefokus hat.

Sie können das VSM-Markup an eine einzelne Ansicht anfügen, oder Sie können es in einer Formatvorlage definieren, wenn es auf mehrere Ansichten angewendet wird. In den nächsten beiden Abschnitten werden diese Ansätze beschrieben.

VSM-Markup in einer Ansicht

Wenn Sie VSM-Markup an eine Entry Ansicht anfügen möchten, trennen Sie zunächst die Entry Start- und Endtags:

<Entry FontSize="18">

</Entry>

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

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

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

    </VisualStateManager.VisualStateGroups>
</Entry>

VisualStateGroups ist eine angefügte bindungsfähige 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, der eine Sammlung von VisualStateGroup-Objekten ist. Fügen Sie innerhalb der VisualStateManager.VisualStateGroups Tags ein Tagpaar VisualStateGroup für jede Gruppe visueller Zustände 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 Klasse VisualStateGroup definiert eine Eigenschaft namens States, die eine Sammlung von VisualState-Objekten ist. States ist die Inhaltseigenschaft , mit VisualStateGroups der Sie die VisualState Tags direkt zwischen den VisualStateGroup Tags einschließen können. (Inhaltseigenschaften werden im Artikel erläutertGrundlegende XAML-Syntax.)

Der nächste Schritt besteht darin, ein Tagpaar für jeden visuellen Zustand in dieser Gruppe einzuschließen. Diese können auch mithilfe x:Name oder Name:

<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 namens Setters, die eine Auflistung von Setter Objekten ist. Dies sind die gleichen Setter-Objekte, die Sie in einem Style-Objekt verwenden.

Setters ist nicht die Inhaltseigenschaft 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 den einzelnen Setters Tags 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 bindungsfähige Eigenschaft unterstützt werden.

Markup ähnlich wie das ist die Basis der VSM-Seite auf der Ansichtsseite im Beispielprogramm. Die Seite enthält drei Entry Ansichten, aber nur der zweite hat 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 als Teil ihrer Trigger Sammlung vorhanden istDataTrigger. Dies bewirkt, dass die Entry Deaktivierung erfolgt, bis etwas in den dritten Entryeingegeben wird. Hier sehen Sie die Seite beim Start unter iOS, Android und dem Universelle Windows-Plattform (UWP):

VSM on View: Deaktiviert

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

Wenn Sie Text in den dritten Entryeingeben, wechselt die zweite Entry in den Zustand "Normal", und der Hintergrund ist jetzt kalkfarben:

VSM on View: Normal

Wenn Sie die zweite EntryBerühren, erhält sie den Eingabefokus. Er wechselt in den Zustand "Relevant" und erweitert sich auf zweimal seine Höhe:

VSM on View: Fokussiert

Beachten Sie, dass der Entry Kalkhintergrund nicht beibehalten wird, wenn er den Eingabefokus erhält. Wenn der Visual State Manager zwischen den visuellen Zuständen wechselt, werden die im vorherigen Zustand eingestellten Eigenschaften aufgehoben. Denken Sie daran, dass sich die visuellen Zustände gegenseitig ausschließen. Der Status "Normal" bedeutet nicht nur, dass der Entry Status aktiviert ist. Dies bedeutet, dass die Entry Option aktiviert ist und keinen Eingabefokus hat.

Wenn sie einen Entry kalkfarbenen Hintergrund im Zustand "Relevant" haben möchten, fügen Sie diesem visuellen Zustand einen weiteren 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 für alle Zustände in dieser Gruppe enthalten VisualState . Wenn ein visueller Zustand vorhanden ist, der keine Objekte enthält Setter , schließen Sie ihn trotzdem als leeres Tag ein:

<VisualState x:Name="Normal" />

Visual State Manager-Markup in einer Formatvorlage

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

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

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

Hinzufügen von Setter Tags für die VisualStateManager.VisualStateGroups angefügte bindungsfähige Eigenschaft:

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

    </Setter>
</Style>

Die Inhaltseigenschaft Setter lautet 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 entspricht dem zuvor.

Hier sehen Sie die VSM-Seite im Stil 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 "Relevant" jetzt eine Sekunde Setter enthält, die jedem Entry kalkfarbenen Hintergrund auch dann einen Eingabefokus verleiht:

VSM im Stil

Visuelle Zustände in Xamarin.Forms

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

Klasse Zustände Weitere Informationen
Button Pressed Visuelle Zustände der Schaltfläche
CheckBox IsChecked CheckBox: visuelle Zuständex
CarouselView DefaultItem, , CurrentItemPreviousItemNextItem CarouselView: visuelle Zustände
ImageButton Pressed ImageButton: visuelle Zustände
RadioButton Checked, Unchecked RadioButton: visuelle Status
Switch On, Off Switch: visuelle Zustände
VisualElement Normal, , DisabledFocusedSelected Allgemeine Status

Auf jeden dieser Zustände kann über die Gruppe visueller Zustände mit dem Namen zugegriffen CommonStateswerden.

Darüber hinaus implementiert Selected der CollectionView Zustand. Weitere Informationen finden Sie unter "Ändern der ausgewählten Elementfarbe".

Festlegen des Zustands für mehrere Elemente

In den vorangegangenen Beispielen wurden visuelle Status einzelnen Elementen beigefügt und auf diese angewendet. Es ist jedoch auch möglich, visuelle Status zu erstellen, die an ein einzelnes Element gebunden sind, aber Eigenschaften für andere Elemente innerhalb desselben Bereichs festlegen. Dadurch wird vermieden, dass die visuellen Status für jedes Element, auf das die Zustände wirken, wiederholt werden müssen.

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

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

In diesem Beispiel wird die Eigenschaft TextColor eines Label namens label auf Red gesetzt. Wenn Sie die Eigenschaft TargetName einstellen, müssen Sie den vollständigen Pfad zur Eigenschaft in Property angeben. Um die Eigenschaft TextColor auf Label zu setzen, wird daher Property als Label.TextColor angegeben.

Hinweis

Jede Eigenschaft, auf die von einem Setter-Objekt verwiesen wird, muss durch eine bindungsfähige Eigenschaft unterstützt werden.

Auf der Seite "VSM mit Setter TargetName " im Beispiel wird gezeigt, wie der Zustand für mehrere Elemente aus einer einzelnen Gruppe visueller Zustände festgelegt wird. Die XAML-Datei besteht aus einem StackLayout Element, einem Label EntryElement und einem 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 die StackLayout. Es gibt zwei sich gegenseitig ausschließende Zustände mit dem Namen "Normal" und "Pressed", wobei jeder Zustand Tags enthält VisualState .

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

VSM Setter TargetName: Normaler Zustand

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

VSM Setter TargetName: Gedrückter Zustand

Das "Pressed" VisualState gibt an, dass die Scale Eigenschaft beim Button Drücken von 1 auf 0,8 geändert wird. Außerdem wird die Entry mit dem Namen entry mit der Eigenschaft Text auf Paris gesetzt. Daher ist das Ergebnis, dass die Button Skalierung bei gedrückter Taste etwas kleiner ist und die Entry Displays Paris. Wenn die Button dann losgelassen wird, wird sie auf ihren Standardwert von 1 zurückgesetzt, und die Entry zeigt jeden zuvor eingegebenen Text an.

Wichtig

Eigenschaftspfade werden derzeit in Setter Elementen, die die TargetName Eigenschaft angeben, nicht unterstützt.

Definieren eigener visueller Zustände

Jede Klasse, die von VisualElement der abgeleitet wird, unterstützt die allgemeinen Zustände "Normal", "Relevant" und "Disabled". Darüber hinaus unterstützt die CollectionView Klasse den Status "Ausgewählt". Intern erkennt die VisualElement Klasse, wann sie aktiviert oder deaktiviert oder 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 basierend auf jeder Klasse aufgerufen wird, von VisualElementder abgeleitet wird, können Sie den Visual State-Manager mit jedem VisualElement Objekt verwenden, um auf diese Änderungen zu reagieren.

Interessanterweise wird nicht explizit auf den Namen der Gruppe "CommonStates" verwiesen VisualElement. Der Gruppenname ist nicht Teil der API für den Visual State Manager. Innerhalb eines der bisher gezeigten beiden 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 die visuellen Zustände in jeder Gruppe sich gegenseitig ausschließen: Ein Zustand und nur ein Zustand ist jederzeit aktuell.

Wenn Sie ihre eigenen visuellen Zustände implementieren möchten, müssen Sie aus Code aufrufen VisualStateManager.GoToState . Meistens führen Sie diesen Aufruf aus der CodeBehind-Datei Ihrer Seitenklasse aus.

Auf der Seite "VSM-Überprüfung" im Beispiel wird gezeigt, wie Der Visual State-Manager in Verbindung mit der Eingabeüberprüfung verwendet wird. Die XAML-Datei besteht aus zwei StackLayout Label Elementen, einem Entryund einem 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 den StackLayout (benannten stackLayout) angefügt. Es gibt zwei sich gegenseitig ausschließende Zustände namens "Valid" und "Invalid", wobei jeder Zustand Tags enthält VisualState .

Wenn die Entry ungültige Telefonnummer nicht enthalten ist, ist der aktuelle Zustand "Ungültig", sodass der Entry hintergrund rosa hintergrund ist, der zweite Label sichtbar ist und deaktiviert Button ist:

VSM-Überprüfung: Ungültiger Zustand

Wenn eine gültige Telefonnummer eingegeben wird, wird der aktuelle Status "Gültig". Das Entry erhält einen hellgrünen Hintergrund, das zweite Label verschwindet, und Button ist jetzt aktiviert:

VSM-Überprüfung: Gültiger Status

Die Code-Behind-Datei ist für die Verarbeitung des TextChanged-Ereignisses von Entry verantwortlich. Der Handler verwendet einen regulären Ausdruck, um festzustellen, ob die Eingabezeichenfolge gültig ist oder nicht. Die Methode in der CodeBehind-Datei mit dem Namen GoToState ruft die statische VisualStateManager.GoToState Methode für stackLayout:

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 einen aktuellen Stand geben. Im Code gibt es jedoch keinen Verweis auf den Namen der Gruppe visueller Zustände, obwohl sie im XAML-Code als "ValidationStates" für Klarheit referenziert wird.

Beachten Sie, dass die CodeBehind-Datei nur das Objekt auf der Seite berücksichtigen muss, das die visuellen Zustände definiert und um dieses Objekt aufzurufen VisualStateManager.GoToState . 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, das die visuellen Zustände definiert, warum kann die CodeBehind-Datei nicht direkt auf dieses und andere Objekte zugreifen? Es könnte sicherlich sein. Der Vorteil der Verwendung von VSM besteht jedoch darin, dass Sie steuern können, wie visuelle Elemente vollständig in XAML auf den unterschiedlichen Zustand reagieren, wodurch das gesamte UI-Design an einer zentralen Stelle erhalten bleibt. Dadurch wird verhindert, dass visuelle Darstellungen festgelegt werden, indem direkt über den CodeBehind auf visuelle Elemente zugegriffen wird.

Auslöser visueller Status

Visuelle Status unterstützen Statusauslöser, bei denen es sich um eine spezielle Gruppe von Auslösern handelt, die die Bedingungen festlegen, 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 Hochformat oder im Querformat angezeigt werden, und ein Xamarin.Forms Programm, das auf dem Desktop ausgeführt wird, kann geändert werden, um viele verschiedene Größen und Seitenverhältnisse anzunehmen. Eine gut gestaltete Anwendung kann ihren Inhalt für diese verschiedenen Seiten- oder Fensterformfaktoren unterschiedlich anzeigen.

Diese Technik wird manchmal als adaptives Layout bezeichnet. Da das adaptive Layout nur die visuellen Elemente 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 Hochformat werden diese Schaltflächen möglicherweise in einer horizontalen Zeile oben auf der Seite angezeigt:

VSM Adaptives Layout: Hochformat

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

VSM Adaptives Layout: Querformat

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

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

VSM-Markup erfolgt an vier Stellen in der XAML-Datei. Der 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 Benannte menuScroll und das StackLayout benannte menuStack Implementieren des Menüs mit Schaltflächen. Die Ausrichtung dieser Layouts ist gegenüber .mainStack Das Menü sollte im Hochformatmodus horizontal und vertikal im Querformatmodus sein.

Der vierte Abschnitt des VSM-Markups weist eine implizite Formatvorlage für die Schaltflächen selbst auf. Dieses Markup legt VerticalOptionsspezifische HorizontalOptionsEigenschaften für Margin Hoch- und Querformat fest.

Die CodeBehind-Datei legt die Eigenschaft für die BindingContext Implementierung Button von menuStack Befehlen fest und fügt außerdem 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 die beiden StackLayout Elemente auf ScrollView und durchläuft dann die untergeordneten Elemente des menuStack Aufrufs VisualStateManager.GoToState für die Button Elemente.

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 strukturierterer Ansatz. Alle visuellen Elemente 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 zum Visual State Manager 3.0