Xamarin.Forms Visual State Manager
Usa Visual State Manager per apportare modifiche agli elementi XAML in base agli stati di visualizzazione impostati dal codice.
Visual State Manager (VSM) offre un modo strutturato per apportare modifiche visive all'interfaccia utente dal codice. Nella maggior parte dei casi, l'interfaccia utente dell'applicazione viene definita in XAML e questo codice XAML include markup che descrivono in che modo Visual State Manager influisce sugli oggetti visivi dell'interfaccia utente.
Vsm introduce il concetto di stati di visualizzazione. Una Xamarin.Forms visualizzazione, ad esempio, Button
può avere diversi aspetti visivi a seconda dello stato sottostante, ovvero se è disabilitata o premuta o ha lo stato attivo per l'input. Questi sono gli stati del pulsante.
Gli stati di visualizzazione vengono raccolti in gruppi di stati di visualizzazione. Tutti gli stati di visualizzazione all'interno di un gruppo di stati di visualizzazione si escludono a vicenda. Sia gli stati di visualizzazione che i gruppi di stati di visualizzazione sono identificati da stringhe di testo semplici.
Xamarin.Forms Visual State Manager definisce un gruppo di stati di visualizzazione denominato "CommonStates" con gli stati di visualizzazione seguenti:
- "Normal"
- "Disabilitato"
- "Incentrato"
- "Selezionato"
Questo gruppo di stati di visualizzazione è supportato per tutte le classi che derivano da VisualElement
, ovvero la classe di base per View
e Page
.
È anche possibile definire gruppi di stati di visualizzazione e stati di visualizzazione personalizzati, come illustrato in questo articolo.
Nota
Xamarin.Forms Gli sviluppatori che hanno familiarità con i trigger sono consapevoli che i trigger possono anche apportare modifiche agli oggetti visivi nell'interfaccia utente in base alle modifiche apportate alle proprietà di una visualizzazione o alla generazione di eventi. Tuttavia, l'uso di trigger per gestire varie combinazioni di queste modifiche può diventare piuttosto confuso. Storicamente, Visual State Manager è stato introdotto negli ambienti basati su XAML di Windows per alleviare la confusione risultante da combinazioni di stati di visualizzazione. Con VSM, gli stati di visualizzazione all'interno di un gruppo di stati di visualizzazione si escludono sempre a vicenda. In qualsiasi momento, solo uno stato in ogni gruppo è lo stato corrente.
Stati comuni
Visual State Manager consente di includere markup nel file XAML che può modificare l'aspetto visivo di una visualizzazione se la visualizzazione è normale o disabilitata o ha lo stato attivo per l'input. Questi sono noti come stati comuni.
Si supponga, ad esempio, di avere una Entry
visualizzazione nella pagina e di voler modificare l'aspetto visivo dell'oggetto Entry
nei modi seguenti:
- L'oggetto
Entry
deve avere uno sfondo rosa quando l'oggettoEntry
è disabilitato. - L'oggetto
Entry
deve avere normalmente uno sfondo lime. - L'oggetto
Entry
deve espandersi fino al doppio dell'altezza normale quando ha lo stato attivo per l'input.
È possibile collegare il markup VSM a una singola visualizzazione oppure definirlo in uno stile se si applica a più visualizzazioni. Le due sezioni successive descrivono questi approcci.
Markup VSM in una visualizzazione
Per associare markup VSM a una Entry
visualizzazione, separare prima di tutto i Entry
tag iniziale e finale:
<Entry FontSize="18">
</Entry>
Viene assegnata una dimensione esplicita del tipo di carattere perché uno degli stati userà la FontSize
proprietà per raddoppiare le dimensioni del testo in Entry
.
VisualStateManager.VisualStateGroups
Inserire quindi tag tra i tag seguenti:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
</VisualStateManager.VisualStateGroups>
</Entry>
VisualStateGroups
è una proprietà associabile associata definita dalla VisualStateManager
classe . Per altre informazioni sulle proprietà associabili associate, vedere l'articolo Proprietà associate. Questo è il modo in cui la VisualStateGroups
proprietà viene associata all'oggetto Entry
.
La VisualStateGroups
proprietà è di tipo VisualStateGroupList
, che è una raccolta di VisualStateGroup
oggetti . All'interno dei VisualStateManager.VisualStateGroups
tag inserire una coppia di VisualStateGroup
tag per ogni gruppo di stati di visualizzazione da includere:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
Si noti che il VisualStateGroup
tag ha un x:Name
attributo che indica il nome del gruppo. La VisualStateGroup
classe definisce invece una Name
proprietà che è possibile usare:
<VisualStateGroup Name="CommonStates">
È possibile usare x:Name
o Name
ma non entrambi nello stesso elemento.
La VisualStateGroup
classe definisce una proprietà denominata States
, che è una raccolta di VisualState
oggetti . States
è la proprietà del contenuto di VisualStateGroups
in modo da poter includere i VisualState
tag direttamente tra i VisualStateGroup
tag. Le proprietà del contenuto sono descritte nell'articolo Sintassi XAML essenziale.
Il passaggio successivo consiste nell'includere una coppia di tag per ogni stato di visualizzazione in tale gruppo. Questi possono essere identificati anche usando x:Name
o 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
definisce una proprietà denominata Setters
, che è una raccolta di Setter
oggetti . Si tratta degli stessi Setter
oggetti usati in un Style
oggetto .
Setters
non è la proprietà content di VisualState
, pertanto è necessario includere i tag degli elementi di proprietà per la Setters
proprietà :
<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>
È ora possibile inserire uno o più Setter
oggetti tra ogni coppia di Setters
tag. Questi sono gli Setter
oggetti che definiscono gli stati di visualizzazione descritti in precedenza:
<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>
Ogni Setter
tag indica il valore di una determinata proprietà quando lo stato è corrente. Qualsiasi proprietà a cui fa riferimento un Setter
oggetto deve essere supportata da una proprietà associabile.
Il markup simile a questo è la base della pagina VSM nella pagina Visualizza nel programma di esempio. La pagina include tre Entry
visualizzazioni, ma solo la seconda include il markup VSM a esso associato:
<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>
Si noti che il secondo Entry
include anche un DataTrigger
oggetto come parte della relativa Trigger
raccolta. In questo modo, l'oggetto Entry
deve essere disabilitato fino a quando non viene digitato un elemento nel terzo Entry
oggetto . Ecco la pagina all'avvio in esecuzione in iOS, Android e la piattaforma UWP (Universal Windows Platform) (UWP):
Lo stato di visualizzazione corrente è "Disabilitato", quindi lo sfondo del secondo Entry
è rosa nelle schermate iOS e Android. L'implementazione UWP di non consente di impostare il colore di Entry
sfondo quando è Entry
disabilitato.
Quando si immette un testo nel terzo Entry
, il secondo Entry
passa allo stato "Normale" e lo sfondo è ora lime:
Quando si tocca il secondo Entry
oggetto , ottiene lo stato attivo dell'input. Passa allo stato "Attivo" e si espande fino al doppio dell'altezza:
Si noti che l'oggetto Entry
non mantiene lo sfondo lime quando ottiene lo stato attivo per l'input. Quando Visual State Manager passa tra gli stati di visualizzazione, le proprietà impostate dallo stato precedente non vengono impostate. Tenere presente che gli stati di visualizzazione si escludono a vicenda. Lo stato "Normale" non significa esclusivamente che Entry
sia abilitato. Significa che Entry
è abilitato e non ha lo stato attivo per l'input.
Se si desidera che l'oggetto Entry
abbia uno sfondo lime nello stato "Con stato attivo", aggiungere un altro Setter
allo stato di visualizzazione:
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
Affinché questi Setter
oggetti funzionino correttamente, un VisualStateGroup
oggetto deve contenere VisualState
oggetti per tutti gli stati in tale gruppo. Se è presente uno stato di visualizzazione che non ha oggetti Setter
, includerlo comunque come tag vuoto:
<VisualState x:Name="Normal" />
Markup di Visual State Manager in uno stile
Spesso è necessario condividere lo stesso markup di Visual State Manager tra due o più visualizzazioni. In questo caso, si vuole inserire il markup in una Style
definizione.
Ecco l'implicito Style
esistente per gli Entry
elementi nella pagina VSM nella visualizzazione :
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
</Style>
Aggiungere Setter
tag per la VisualStateManager.VisualStateGroups
proprietà associabile associata:
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
</Setter>
</Style>
La proprietà content per Setter
è Value
, quindi il valore della proprietà può essere specificato direttamente all'interno di Value
tali tag. Tale proprietà è di tipo VisualStateGroupList
:
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
</VisualStateGroupList>
</Setter>
</Style>
All'interno di questi tag è possibile includere uno di più VisualStateGroup
oggetti:
<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>
Il resto del markup VSM è identico a quello precedente.
Ecco la pagina VSM in Stile che mostra il markup VSM completo:
<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>
Ora tutte le Entry
visualizzazioni in questa pagina rispondono allo stesso modo degli stati di visualizzazione. Si noti anche che lo stato "Focus" include ora un secondo Setter
che fornisce a ogni Entry
sfondo lime anche quando ha lo stato attivo per l'input:
Stati di visualizzazione in Xamarin.Forms
Nella tabella seguente sono elencati gli stati di visualizzazione definiti in Xamarin.Forms:
Classe | Stati | Ulteriori informazioni |
---|---|---|
Button |
Pressed |
Stati di visualizzazione pulsante |
CheckBox |
IsChecked |
Stati di visualizzazione CheckBox |
CarouselView |
DefaultItem , CurrentItem , PreviousItem NextItem |
Stati di visualizzazione CarouselView |
ImageButton |
Pressed |
Stati di visualizzazione ImageButton |
RadioButton |
Checked , Unchecked |
Stati di visualizzazione RadioButton |
Switch |
On , Off |
Cambiare gli stati di visualizzazione |
VisualElement |
Normal , Disabled , Focused Selected |
Stati comuni |
È possibile accedere a ognuno di questi stati tramite il gruppo di stati di visualizzazione denominato CommonStates
.
Inoltre, CollectionView
implementa lo Selected
stato . Per altre informazioni, vedere Modificare il colore dell'elemento selezionato.
Impostare lo stato su più elementi
Negli esempi precedenti gli stati di visualizzazione sono stati collegati a e gestiti su singoli elementi. Tuttavia, è anche possibile creare stati di visualizzazione collegati a un singolo elemento, ma che impostano proprietà su altri elementi all'interno dello stesso ambito. In questo modo si evita di dover ripetere gli stati di visualizzazione in ogni elemento su cui operano gli stati.
Il Setter
tipo ha una TargetName
proprietà di tipo string
, che rappresenta l'elemento di destinazione che verrà Setter
modificato da per uno stato di visualizzazione. Quando la TargetName
proprietà è definita, imposta Setter
l'oggetto Property
dell'elemento definito in TargetName
su Value
:
<Setter TargetName="label"
Property="Label.TextColor"
Value="Red" />
In questo esempio, un Label
oggetto denominato label
avrà la relativa TextColor
proprietà impostata su Red
. Quando si imposta la TargetName
proprietà è necessario specificare il percorso completo della proprietà in Property
. Pertanto, per impostare la TextColor
proprietà in un Label
oggetto , Property
viene specificato come Label.TextColor
.
Nota
Qualsiasi proprietà a cui fa riferimento un Setter
oggetto deve essere supportata da una proprietà associabile.
La pagina VSM con Setter TargetName nell'esempio mostra come impostare lo stato su più elementi, da un singolo gruppo di stati di visualizzazione. Il file XAML è costituito da un StackLayout
oggetto contenente un Label
elemento, un oggetto Entry
e un Button
oggetto :
<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>
Il markup VSM è associato a StackLayout
. Esistono due stati che si escludono a vicenda, denominati "Normal" e "Pressed", con ogni stato contenente VisualState
tag.
Lo stato "Normale" è attivo quando Button
non viene premuto e una risposta alla domanda può essere immessa:
Lo stato "Premuto" diventa attivo quando Button
viene premuto:
La proprietà "Pressed" VisualState
specifica che, quando Button
viene premuto, la relativa Scale
proprietà verrà modificata dal valore predefinito da 1 a 0,8. Inoltre, la Entry
proprietà denominata entry
sarà Text
impostata su Parigi. Di conseguenza, il risultato è che quando viene premuto viene Button
ridimensionato per essere leggermente più piccolo, e le Entry
visualizzazioni di Parigi. Quindi, quando viene Button
rilasciato, viene ridimensionato in base al valore predefinito 1 e Entry
visualizza qualsiasi testo immesso in precedenza.
Importante
I percorsi delle proprietà non sono attualmente supportati negli Setter
elementi che specificano la TargetName
proprietà .
Definire i propri stati di visualizzazione
Ogni classe che deriva da VisualElement
supporta gli stati comuni "Normal", "Focus" e "Disabled". Inoltre, la CollectionView
classe supporta lo stato "Selected". Internamente, la VisualElement
classe rileva quando diventa abilitata o disabilitata o con stato attivo o non attivo e chiama il metodo statico VisualStateManager.GoToState
:
VisualStateManager.GoToState(this, "Focused");
Si tratta dell'unico codice di Visual State Manager disponibile nella VisualElement
classe . Poiché GoToState
viene chiamato per ogni oggetto basato su ogni classe che deriva da VisualElement
, è possibile usare Visual State Manager con qualsiasi VisualElement
oggetto per rispondere a queste modifiche.
È interessante notare che il nome del gruppo di stati di visualizzazione "CommonStates" non viene fatto riferimento in modo esplicito in VisualElement
. Il nome del gruppo non fa parte dell'API per Visual State Manager. All'interno di uno dei due programmi di esempio mostrati finora, è possibile modificare il nome del gruppo da "CommonStates" a qualsiasi altro elemento e il programma funzionerà ancora. Il nome del gruppo è semplicemente una descrizione generale degli stati in tale gruppo. Si è compreso in modo implicito che gli stati di visualizzazione in qualsiasi gruppo si escludono a vicenda: uno stato e un solo stato è corrente in qualsiasi momento.
Se si vogliono implementare stati di visualizzazione personalizzati, è necessario chiamare VisualStateManager.GoToState
dal codice. La maggior parte delle volte si effettua questa chiamata dal file code-behind della classe di pagina.
La pagina Convalida VSM nell'esempio mostra come usare Visual State Manager in connessione con la convalida dell'input. Il file XAML è costituito da un StackLayout
oggetto contenente due Label
elementi, un Entry
oggetto e un Button
oggetto :
<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>
Il markup VSM è associato a StackLayout
(denominato stackLayout
). Esistono due stati che si escludono a vicenda, denominati "Valid" e "Invalid", con ogni stato contenente VisualState
i tag.
Se l'oggetto Entry
non contiene un numero di telefono valido, lo stato corrente è "Non valido", quindi ha Entry
uno sfondo rosa, il secondo Label
è visibile e viene Button
disabilitato:
Quando viene immesso un numero di telefono valido, lo stato corrente diventa "Valido". Ottiene Entry
uno sfondo lime, il secondo Label
scompare e ora Button
è abilitato:
Il file code-behind è responsabile della gestione dell'evento TextChanged
da Entry
. Il gestore usa un'espressione regolare per determinare se la stringa di input è valida o meno. Il metodo nel file code-behind denominato GoToState
chiama il metodo statico VisualStateManager.GoToState
per 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);
}
}
Si noti anche che il GoToState
metodo viene chiamato dal costruttore per inizializzare lo stato. Dovrebbe esserci sempre uno stato corrente. Tuttavia, nel codice non è presente alcun riferimento al nome del gruppo di stati di visualizzazione, anche se viene fatto riferimento nel codice XAML come "ValidationStates" a scopo di chiarezza.
Si noti che il file code-behind deve tenere conto solo dell'oggetto nella pagina che definisce gli stati di visualizzazione e di chiamare VisualStateManager.GoToState
per questo oggetto. Questo perché entrambi gli stati di visualizzazione hanno come destinazione più oggetti nella pagina.
Ci si potrebbe chiedere: se il file code-behind deve fare riferimento all'oggetto nella pagina che definisce gli stati di visualizzazione, perché il file code-behind non può semplicemente accedere direttamente a questo e ad altri oggetti? Sicuramente potrebbe. Tuttavia, il vantaggio dell'uso di VSM è che è possibile controllare il modo in cui gli elementi visivi reagiscono completamente allo stato in XAML, che mantiene tutta la progettazione dell'interfaccia utente in un'unica posizione. In questo modo si evita di impostare l'aspetto visivo accedendo agli elementi visivi direttamente dal code-behind.
Trigger dello stato di visualizzazione
Gli stati di visualizzazione supportano i trigger di stato, ovvero un gruppo specializzato di trigger che definiscono le condizioni in cui deve essere applicato un oggetto VisualState
.
I trigger di stato vengono aggiunti alla raccolta StateTriggers
di VisualState
. Questa raccolta può contenere un solo o più trigger di stato. VisualState
viene applicato quando nella raccolta è attivo un qualsiasi trigger di stato.
Quando si usano trigger di stato per controllare gli stati di visualizzazione, Xamarin.Forms usa le regole di precedenza seguenti per determinare quale trigger (e corrispondente VisualState
) sarà attivo:
- Qualsiasi trigger che derivi da
StateTriggerBase
. AdaptiveTrigger
attivato perché la condizioneMinWindowWidth
è soddisfatta.AdaptiveTrigger
attivato perché la condizioneMinWindowHeight
è soddisfatta.
Se sono attivi più trigger, ad esempio due trigger personalizzati, contemporaneamente, il primo trigger dichiarato nel markup ha la precedenza.
Per altre informazioni sui trigger di stato, vedere Trigger di stato.
Usare Visual State Manager per il layout adattivo
Un'applicazione Xamarin.Forms in esecuzione su un telefono può in genere essere visualizzata in proporzioni verticale o orizzontale e un Xamarin.Forms programma in esecuzione sul desktop può essere ridimensionato per assumere molte dimensioni e proporzioni diverse. Un'applicazione ben progettata potrebbe visualizzarne il contenuto in modo diverso per questi vari fattori di forma di pagina o finestra.
Questa tecnica è talvolta nota come layout adattivo. Poiché il layout adattivo prevede esclusivamente gli oggetti visivi di un programma, è un'applicazione ideale di Visual State Manager.
Un semplice esempio è un'applicazione che visualizza una piccola raccolta di pulsanti che influiscono sul contenuto dell'applicazione. In modalità verticale, questi pulsanti potrebbero essere visualizzati in una riga orizzontale nella parte superiore della pagina:
In modalità orizzontale, la matrice di pulsanti potrebbe essere spostata su un lato e visualizzata in una colonna:
Dall'alto verso il basso, il programma è in esecuzione nel piattaforma UWP (Universal Windows Platform), Android e iOS.
La pagina Layout adattivo VSM nell'esempio definisce un gruppo denominato "OrientationStates" con due stati di visualizzazione denominati "Verticale" e "Orizzontale". Un approccio più complesso potrebbe essere basato su diverse larghezze di pagina o finestra.
Il markup VSM si verifica in quattro posizioni nel file XAML. L'oggetto StackLayout
denominato mainStack
contiene sia il menu che il contenuto, ovvero un Image
elemento . Deve StackLayout
avere un orientamento verticale in modalità verticale e un orientamento orizzontale in modalità orizzontale:
<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>
Il nome menuScroll
interno ScrollView
e il StackLayout
denominato menuStack
implementano il menu dei pulsanti. L'orientamento di questi layout è opposto a mainStack
. Il menu deve essere orizzontale in modalità verticale e verticale in modalità orizzontale.
La quarta sezione del markup VSM è in uno stile implicito per i pulsanti stessi. Questo markup imposta VerticalOptions
le proprietà , HorizontalOptions
e Margin
specifiche per l'orientamento verticale e orizzontale.
Il file code-behind imposta la BindingContext
proprietà di menuStack
per implementare Button
i comandi e associa anche un gestore all'evento SizeChanged
della pagina:
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; }
}
Il SizeChanged
gestore chiama VisualStateManager.GoToState
i due StackLayout
elementi e ScrollView
e quindi esegue un ciclo tra gli elementi figlio di menuStack
per chiamare VisualStateManager.GoToState
gli Button
elementi.
Può sembrare come se il file code-behind possa gestire le modifiche di orientamento più direttamente impostando le proprietà degli elementi nel file XAML, ma Visual State Manager è sicuramente un approccio più strutturato. Tutti gli oggetti visivi vengono mantenuti nel file XAML, in cui diventano più facili da esaminare, gestire e modificare.
Visual State Manager con Xamarin.University
Xamarin.Forms Video di Visual State Manager 3.0