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 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 VisualElement
abgeleitet 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 deaktiviertEntry
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 Entry
zu 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 Name
identifiziert 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 Entry
eingegeben wird. Dies ist die Seite beim Start unter iOS, Android und dem Universelle Windows-Plattform (UWP):
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 Entry
eingeben, wechselt der zweite Entry
in den Zustand "Normal", und der Hintergrund ist nun lime:
Wenn Sie den zweiten Entry
berühren, erhält er den Eingabefokus. Er wechselt in den Status "Fokussiert" und wird auf die doppelte Höhe erweitert:
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:
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 CommonStates
zugegriffen 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 label
TextColor
auf Red
festgelegt. Beim Festlegen der TargetName
-Eigenschaft müssen Sie den vollständigen Pfad zur -Eigenschaft in Property
angeben. Daher wird zum Festlegen der TextColor
-Eigenschaft auf einem Property
Label
als Label.TextColor
angegeben.
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 StackLayout
angefü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:
Der Zustand "Gedrückt" wird aktiv, wenn gedrückt Button
wird:
"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 VisualElement
abgeleitet wird, können Sie den Visual State Manager mit jedem VisualElement
-Objekt verwenden, um auf diese Änderungen zu reagieren.
Interessanterweise wird in VisualElement
nicht 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: Entry
und 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:
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:
Die CodeBehind-Datei ist für die Behandlung des TextChanged
-Ereignisses aus dem Entry
verantwortlich. 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 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);
}
}
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:
- Alle von
StateTriggerBase
abgeleiteten Trigger. - Ein
AdaptiveTrigger
, der aktiviert wird, da die BedingungMinWindowWidth
erfüllt ist. - Ein
AdaptiveTrigger
, der aktiviert wird, da die BedingungMinWindowHeight
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:
Im Querformatmodus kann das Array von Schaltflächen auf eine Seite verschoben und in einer Spalte angezeigt werden:
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 VerticalOptions
eigenschaften , HorizontalOptions
und 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