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 VisualElement
der 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 derEntry
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 Entry
Text 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 Entry
eingegeben wird. Hier sehen Sie die Seite beim Start unter iOS, Android und dem Universelle Windows-Plattform (UWP):
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 Entry
eingeben, wechselt die zweite Entry
in den Zustand "Normal", und der Hintergrund ist jetzt kalkfarben:
Wenn Sie die zweite Entry
Berühren, erhält sie den Eingabefokus. Er wechselt in den Zustand "Relevant" und erweitert sich auf zweimal seine Höhe:
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:
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 , , CurrentItem PreviousItem NextItem |
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 , , Disabled Focused Selected |
Allgemeine Status |
Auf jeden dieser Zustände kann über die Gruppe visueller Zustände mit dem Namen zugegriffen CommonStates
werden.
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
Entry
Element 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:
Der Zustand "Gedrückt" wird aktiv, wenn die Button
Taste gedrückt wird:
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 VisualElement
der 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 Entry
und 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:
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:
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:
- 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 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:
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 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 VerticalOptions
spezifische HorizontalOptions
Eigenschaften 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