Visueller Zustand

Der .NET Multi-Platform App UI (.NET MAUI) Visual State Manager bietet eine strukturierte Möglichkeit, visuelle Änderungen an der Benutzeroberfläche vom Code aus vorzunehmen. In den meisten Fällen wird die Benutzeroberfläche einer Anwendung in XAML definiert, und diese XAML kann Markup enthalten, das beschreibt, wie der Visual State Manager die visuelle Darstellung der Benutzeroberfläche beeinflusst.

Der Visual State Manager führt das Konzept der visuellen Zustände ein. Eine .NET MAUI-Ansicht, wie etwa Button, kann je nach ihrem zugrunde liegenden Status – ob sie deaktiviert oder gedrückt ist oder den Eingabefokus hat – verschiedene visuelle Erscheinungsbilder haben. 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 .NET MAUI Visual State Manager definiert eine visuelle Statusgruppe namens CommonStates mit den folgenden visuellen Status:

  • Normal
  • Disabled
  • Fokus
  • Ausgewählt
  • PointerOver

Die visuellen Zustände Normal, Disabled, Focused und PointerOver werden von allen Klassen unterstützt, die von VisualElement abgeleitet sind, der Basisklasse für View und Page. Darüber hinaus können Sie auch Ihre eigenen visuellen Zustandsgruppen und visuellen Zustände definieren.

Der Vorteil der Verwendung des Visual State Managers zur Definition des Erscheinungsbildes gegenüber dem direkten Zugriff auf visuelle Elemente über Code-Behind ist, dass Sie die Reaktion der visuellen Elemente auf verschiedene Status vollständig in XAML steuern können, wodurch das gesamte UI-Design an einem Ort bleibt.

Hinweis

Auslöser können auch Änderungen an der visuellen Darstellung der Benutzeroberfläche vornehmen, die auf Änderungen der Eigenschaften einer Ansicht oder dem Auslösen von Ereignissen basieren. Die Verwendung von Auslösern für verschiedene Kombinationen dieser Änderungen kann jedoch verwirrend werden. Mit dem Visual State Manager 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.

Gängige visuelle Zustände

Mit dem Visual State Manager können Sie Markups in Ihre XAML-Datei einfügen, die das visuelle Erscheinungsbild einer Ansicht ändern, wenn die Ansicht normal oder deaktiviert ist, den Eingabefokus hat, ausgewählt ist oder der Mauszeiger über ihr schwebt, aber nicht gedrückt ist. 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.
  • Entry sollte einen hellblauen Hintergrund haben, wenn der Mauszeiger darüber schwebt, aber nicht gedrückt ist.

Sie können das Visual State Manager Markup an eine einzelne Ansicht anhängen oder es in einem Stil definieren, wenn es für mehrere Ansichten gilt.

Definition visueller Status in einer Ansicht

Die VisualStateManager-Klasse definiert eine angehängte Eigenschaft VisualStateGroups, die verwendet wird, um visuelle Zustände an eine Ansicht anzuhängen. Die VisualStateGroups-Eigenschaft ist vom Typ VisualStateGroupList, der eine Sammlung von VisualStateGroup-Objekten ist. Daher ist das untergeordnete Element der angehängten Eigenschaft VisualStateManager.VisualStateGroups ein VisualStateGroup-Objekt. Dieses Objekt definiert ein x:Name-Attribut, das den Namen der Gruppe angibt. Alternativ dazu definiert die Klasse VisualStateGroup eine Eigenschaft Name, die Sie stattdessen verwenden können. Weitere Informationen zu angefügten Eigenschaften finden Sie unter Angefügte Eigenschaften.

Die Klasse VisualStateGroup definiert eine Eigenschaft namens States, die eine Sammlung von VisualState-Objekten ist. States ist die Inhaltseigenschaft der Klasse VisualStateGroups, so dass Sie die VisualState-Objekte als untergeordnete Elemente der Klasse VisualStateGroup einschließen können. Jedes VisualState-Objekt sollte mit x:Name oder Name gekennzeichnet werden.

Die Klasse VisualState definiert eine Eigenschaft namens Setters, die eine Sammlung 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 notwendig, Eigenschaftselement-Tags für die Setters-Eigenschaft einzufügen. Setter Objekte sollten als untergeordnete Elemente von Setters eingefügt werden. Jedes Setter-Objekt gibt den Wert einer 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.

Wichtig

Damit die Setter-Objekte für den visuellen Zustand korrekt funktionieren, muss ein VisualStateGroup-Objekt ein VisualState-Objekt für den Normal-Zustand enthalten. Wenn dieser visuelle Status keine Setter-Objekte enthält, sollte er als leerer visueller Status (<VisualState Name="Normal" />) eingeschlossen werden.

Das folgende Beispiel zeigt visuelle Status, die für einen Entry definiert sind:

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

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

            <VisualState Name="Disabled">
                <VisualState.Setters>
                    <Setter Property="BackgroundColor" Value="Pink" />
                </VisualState.Setters>
            </VisualState>

            <VisualState Name="PointerOver">
                <VisualState.Setters>
                    <Setter Property="BackgroundColor" Value="LightBlue" />
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Entry>

Der folgende Screenshot zeigt den Entry in seinen vier definierten visuellen Zuständen:

Screenshot der drei definierten visuellen Zustände für den Eintrag.

Wenn sich Entry im Zustand Normal befindet, ist sein Hintergrund hellgrün. Wenn Entry den Eingabefokus erhält, verdoppelt sich die Schriftgröße. Wenn Entry deaktiviert wird, wird der Hintergrund rosa. Entry behält seinen hellgrünen Hintergrund nicht bei, wenn er den Eingabefokus erhält. Wenn der Mauszeiger über dem Entry schwebt, aber nicht gedrückt wird, wird der Entry-Hintergrund hellblau. Wenn der Visual State Manager zwischen den visuellen Zuständen wechselt, werden die im vorherigen Zustand eingestellten Eigenschaften aufgehoben. Daher schließen sich die visuellen Status gegenseitig aus.

Wenn das Entry im Status Focused einen hellen Hintergrund haben soll, fügen Sie ein weiteres Setter zu diesem visuellen Status hinzu:

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

Visuelle Zustände in einem Stil definieren

Oft ist es notwendig, dieselben visuellen Zustände in zwei oder mehr Ansichten gemeinsam zu nutzen. In diesem Szenario können die visuellen Zustände in einem Style definiert werden. Dies kann durch Hinzufügen eines Setter-Objekts für die VisualStateManager.VisualStateGroups-Eigenschaft erreicht werden. Die Inhaltseigenschaft für das Setter-Objekt ist seine Value-Eigenschaft, die daher als untergeordnetes Objekt des Setter-Objekts angegeben werden kann. Die VisualStateGroups-Eigenschaft ist vom Typ VisualStateGroupList, und so ist das untergeordnete Objekt des Setter-Objekts ein VisualStateGroupList, dem ein VisualStateGroup hinzugefügt werden kann, das VisualState-Objekte enthält.

Das folgende Beispiel zeigt einen impliziten Stil für einen Entry, der die gemeinsamen visuellen Status definiert:

<Style TargetType="Entry">
    <Setter Property="FontSize" Value="18" />
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>
            <VisualStateGroup Name="CommonStates">
                <VisualState Name="Normal">
                    <VisualState.Setters>
                        <Setter Property="BackgroundColor" Value="Lime" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState Name="Focused">
                    <VisualState.Setters>
                        <Setter Property="FontSize" Value="36" />
                        <Setter Property="BackgroundColor" Value="Lime" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState Name="Disabled">
                    <VisualState.Setters>
                        <Setter Property="BackgroundColor" Value="Pink" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState Name="PointerOver">
                    <VisualState.Setters>
                        <Setter Property="BackgroundColor" Value="LightBlue" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateGroupList>
    </Setter>
</Style>

Wenn dieser Stil in ein Ressourcenwörterbuch auf Seitenebene aufgenommen wird, wird das Style-Objekt auf alle Entry-Objekte auf der Seite angewendet. Daher reagieren alle Entry-Objekte auf der Seite in gleicher Weise auf ihre visuellen Status.

Visuelle Zustände in .NET MAUI

In der folgenden Tabelle sind die visuellen Zustände aufgeführt, die in .NET MAUI definiert sind:

Klasse Zustände Weitere Informationen
Button Pressed Visuelle Zustände der Schaltfläche
CarouselView DefaultItem, CurrentItem, PreviousItem, NextItem CarouselView: visuelle Zustände
CheckBox IsChecked CheckBox: visuelle Zuständex
CollectionView Selected CollectionView: visuelle Zustände
ImageButton Pressed ImageButton: visuelle Zustände
RadioButton Checked, Unchecked RadioButton: visuelle Status
Switch On, Off Switch: visuelle Zustände
VisualElement Normal, Disabled, Focused, PointerOver Allgemeine Status

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 hat eine TargetName-Eigenschaft vom Typ string, die das Zielobjekt darstellt, das der Setter für einen visuellen Zustand manipulieren wird. Wenn die Eigenschaft TargetName definiert ist, setzt Setter die Property des in TargetName definierten Objekts auf 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.

Das folgende Beispiel zeigt, wie der Zustand mehrerer Objekte über eine einzige visuelle Zustandsgruppe festgelegt werden kann:

<StackLayout>
    <Label Text="What is the capital of France?" />
    <Entry x:Name="entry"
           Placeholder="Enter answer" />
    <Button Text="Reveal answer">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup Name="CommonStates">
                <VisualState Name="Normal" />
                <VisualState 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>

In diesem Beispiel ist der Zustand Normal aktiv, wenn die Taste Button nicht gedrückt wird, und eine Antwort kann in die Taste Entry eingegeben werden. Der Status Pressed wird aktiv, wenn die Taste Button gedrückt wird, und legt fest, dass seine Eigenschaft Scale vom Standardwert 1 in 0,8 geändert wird. Außerdem wird die Entry mit dem Namen entry mit der Eigenschaft Text auf Paris gesetzt. Das Ergebnis ist also, dass die Button beim Drücken etwas kleiner skaliert wird und die Entry Paris anzeigt:

Screenshot des Zustands „Gedrückt“ für eine Schaltfläche.

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 in Setter-Elementen, die die TargetName-Eigenschaft angeben, nicht unterstützt.

Definieren benutzerdefinierter visueller Status

Benutzerdefinierte visuelle Status können implementiert werden, indem man sie so definiert, wie man visuelle Status für die allgemeinen Status definieren würde, jedoch mit Namen Ihrer Wahl, und dann die Methode VisualStateManager.GoToState aufruft, um einen Status zu aktivieren.

Das folgende Beispiel zeigt, wie Sie den Visual State Manager für die Eingabevalidierung verwenden:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             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="18" />
        <Entry x:Name="entry"
               Placeholder="555-555-5555"
               FontSize="18"
               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="18"
                Margin="0, 20"
                VerticalOptions="Center"
                HorizontalOptions="Center" />
    </StackLayout>
</ContentPage>

In diesem Beispiel sind visuelle Zustände an StackLayout angehängt, und es gibt zwei sich gegenseitig ausschließende Zustände namens Valid und Invalid. Wenn Entry keine gültige Telefonnummer enthält, dann ist der aktuelle Status Invalid, und somit hat Entry einen rosa Hintergrund, das zweite Label ist sichtbar und Button ist deaktiviert. Wenn eine gültige Rufnummer eingegeben wird, wird der aktuelle Zustand zu Valid. Das Entry erhält einen hellgrünen Hintergrund, das zweite Label verschwindet, und Button ist jetzt aktiviert:

Screenshot des Beispiels für die Überprüfung des visuellen Zustands.

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 GoToState in der Code-Behind-Datei ruft die statische Methode VisualStateManager.GoToState des Objekts StackLayout auf:

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);
    }
}

In diesem Beispiel wird die Methode GoToState vom Konstruktor aus aufgerufen, um den Zustand zu initialisieren. Es sollte immer einen aktuellen Stand geben. Die Code-Behind-Datei ruft dann VisualStateManager.GoToState mit einem Zustandsnamen für das Objekt auf, das die visuellen Zustände definiert.

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 verwendet .NET MAUI die folgenden Prioritätsregeln, um zu bestimmen, welcher Trigger (und welches entsprechende VisualState) 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.