Udostępnij za pośrednictwem


Xamarin.Forms Visual State Manager

Użyj programu Visual State Manager, aby wprowadzić zmiany w elementach XAML na podstawie stanów wizualizacji ustawionych na podstawie kodu.

Program Visual State Manager (VSM) zapewnia ustrukturyzowany sposób wprowadzania zmian wizualnych w interfejsie użytkownika z kodu. W większości przypadków interfejs użytkownika aplikacji jest definiowany w języku XAML, a ten kod XAML zawiera znaczniki opisujące wpływ programu Visual State Manager na wizualizacje interfejsu użytkownika.

Program VSM wprowadza koncepcję stanów wizualizacji. Widok Xamarin.Forms taki jak Button może mieć kilka różnych wyglądów wizualizacji w zależności od jego stanu bazowego — niezależnie od tego, czy jest wyłączony, czy naciśnięty, czy też ma fokus wejściowy. Są to stany przycisku.

Stany wizualizacji są zbierane w grupach stanu wizualizacji. Wszystkie stany wizualizacji w grupie stanu wizualizacji wykluczają się wzajemnie. Zarówno stany wizualizacji, jak i grupy stanów wizualnych są identyfikowane przez proste ciągi tekstowe.

Program Xamarin.Forms Visual State Manager definiuje jedną grupę stanu wizualizacji o nazwie "CommonStates" z następującymi stanami wizualnymi:

  • "Normalny"
  • "Wyłączone"
  • "Ukierunkowane"
  • "Wybrane"

Ta grupa stanów wizualizacji jest obsługiwana dla wszystkich klas, które pochodzą z VisualElementklasy , która jest klasą bazową dla View i Page.

Możesz również zdefiniować własne grupy stanów wizualnych i stany wizualne, jak pokazano w tym artykule.

Uwaga

Xamarin.Forms deweloperzy zaznajomieni z wyzwalaczami wiedzą, że wyzwalacze mogą również wprowadzać zmiany w wizualizacjach w interfejsie użytkownika na podstawie zmian we właściwościach widoku lub wyzwalaniu zdarzeń. Jednak użycie wyzwalaczy do obsługi różnych kombinacji tych zmian może stać się dość mylące. Historycznie program Visual State Manager został wprowadzony w środowiskach opartych na języku XAML systemu Windows, aby złagodzić zamieszanie wynikające z kombinacji stanów wizualizacji. W przypadku programu VSM stany wizualizacji w grupie stanu wizualizacji zawsze wykluczają się wzajemnie. W dowolnym momencie tylko jeden stan w każdej grupie jest bieżącym stanem.

Wspólne stany

Program Visual State Manager umożliwia dołączenie znaczników do pliku XAML, który może zmienić wygląd wizualizacji widoku, jeśli widok jest normalny lub wyłączony lub ma fokus wejściowy. Są one znane jako wspólne stany.

Załóżmy na przykład, że masz Entry widok na stronie i chcesz, aby wygląd wizualizacji Entry zmienił się w następujący sposób:

  • Element Entry powinien mieć różowe tło, gdy Entry element jest wyłączony.
  • Powinno Entry mieć tło wapna normalnie.
  • Element Entry powinien rozwinąć się do dwukrotnie większej normalnej wysokości, gdy ma fokus wejściowy.

Możesz dołączyć znacznik VSM do pojedynczego widoku lub zdefiniować go w stylu, jeśli ma zastosowanie do wielu widoków. W dwóch następnych sekcjach opisano te podejścia.

Znaczniki programu VSM w widoku

Aby dołączyć znaczniki programu VSM do Entry widoku, najpierw rozdziel tagi Entry początkowe i końcowe:

<Entry FontSize="18">

</Entry>

Ma on jawny rozmiar czcionki, ponieważ jeden ze stanów użyje FontSize właściwości , aby podwoić rozmiar tekstu w pliku Entry.

Następnie wstaw VisualStateManager.VisualStateGroups tagi między tymi tagami:

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

    </VisualStateManager.VisualStateGroups>
</Entry>

VisualStateGroups jest dołączoną właściwością powiązaną zdefiniowaną przez klasę VisualStateManager . (Aby uzyskać więcej informacji na temat dołączonych właściwości możliwych do powiązania, zobacz artykuł Dołączone właściwości). W ten sposób VisualStateGroups właściwość jest dołączona do Entry obiektu.

Właściwość VisualStateGroups jest typu VisualStateGroupList, który jest kolekcją VisualStateGroup obiektów. W tagach VisualStateManager.VisualStateGroups wstaw parę tagów VisualStateGroup dla każdej grupy stanów wizualizacji, które chcesz uwzględnić:

<Entry FontSize="18">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">

        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Entry>

Zwróć uwagę, że VisualStateGroup tag ma x:Name atrybut wskazujący nazwę grupy. Klasa VisualStateGroup definiuje Name właściwość, której można użyć zamiast tego:

<VisualStateGroup Name="CommonStates">

Można użyć elementu x:Name lub Name , ale nie obu w tym samym elemecie.

Klasa VisualStateGroup definiuje właściwość o nazwie States, która jest kolekcją VisualState obiektów. Statesjest właściwością VisualStateGroups zawartości , dzięki czemu można dołączyć VisualState tagi bezpośrednio między tagamiVisualStateGroup. (Właściwości zawartości zostały omówione w artykule Podstawowa składnia XAML).

Następnym krokiem jest dołączenie pary tagów dla każdego stanu wizualizacji w tej grupie. Można je również zidentyfikować przy użyciu polecenia x:Name lub 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 definiuje właściwość o nazwie Setters, która jest kolekcją Setter obiektów. Są to te same Setter obiekty, których używasz w Style obiekcie.

Settersnie jest właściwością VisualStatezawartości klasy , dlatego należy uwzględnić tagi elementów właściwości dla Setters właściwości:

<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>

Teraz można wstawić jeden lub więcej Setter obiektów między każdą parą tagów Setters . Setter Są to obiekty, które definiują opisane wcześniej stany wizualizacji:

<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>

Każdy Setter tag wskazuje wartość określonej właściwości, gdy ten stan jest bieżący. Każda właściwość, do którego Setter odwołuje się obiekt, musi być wspierana przez właściwość, którą można powiązać.

Znaczniki podobne do tego są podstawą strony VSM w widoku w przykładowym programie. Strona zawiera trzy Entry widoki, ale tylko drugi ma dołączony znacznik VSM:

<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>

Zwróć uwagę, że drugi Entry element jest DataTrigger również częścią swojej Trigger kolekcji. Spowoduje to wyłączenie elementu Entry , dopóki coś nie zostanie wpisane do trzeciego Entryelementu . Oto strona uruchamiania uruchomiona w systemach iOS, Android i platforma uniwersalna systemu Windows (UWP):

Program VSM w widoku: wyłączone

Bieżący stan wizualizacji to "Wyłączone", więc tło drugiego Entry jest różowe na ekranach systemów iOS i Android. Implementacja platformy uniwersalnej systemu Entry Windows nie zezwala na ustawianie koloru tła, gdy Entry element jest wyłączony.

Gdy wprowadzisz jakiś tekst w trzecim Entry, drugi Entry przełączy się w stan "Normalny", a tło będzie teraz wapna:

Program VSM w widoku: normalny

Gdy dotkniesz drugiego Entryelementu , zostanie wyświetlony fokus danych wejściowych. Przełącza się na stan "Skoncentrowany" i rozszerza się do dwukrotnie większej wysokości:

Program VSM w widoku: skoncentrowany

Zwróć uwagę, że Entry tło wapna nie zachowuje się, gdy pobiera fokus danych wejściowych. Gdy program Visual State Manager przełącza się między stanami wizualizacji, właściwości ustawione przez poprzedni stan nie są ustawiane. Należy pamiętać, że stany wizualizacji wzajemnie się wykluczają. Stan "Normalny" nie oznacza wyłącznie, że Entry jest włączony. Oznacza to, że Entry parametr jest włączony i nie ma fokusu danych wejściowych.

Jeśli chcesz Entry , aby tło wapna było w stanie "Skoncentrowane", dodaj kolejny Setter element do tego stanu wizualizacji:

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

Aby te Setter obiekty działały prawidłowo, VisualStateGroup obiekt musi zawierać VisualState obiekty dla wszystkich stanów w tej grupie. Jeśli istnieje stan wizualizacji, który nie ma żadnych Setter obiektów, dołącz go mimo to jako pusty tag:

<VisualState x:Name="Normal" />

Znaczniki programu Visual State Manager w stylu

Często konieczne jest współużytkowanie tego samego znacznika programu Visual State Manager między co najmniej dwoma widokami. W takim przypadku należy umieścić znaczniki w Style definicji.

Oto istniejąca niejawna Style funkcja Entry dla elementów na stronie Widok w programie VSM:

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

Dodaj Setter tagi dla dołączonej właściwości możliwej VisualStateManager.VisualStateGroups do powiązania:

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

    </Setter>
</Style>

Właściwość content dla Setter parametru to Value, więc wartość Value właściwości można określić bezpośrednio w tych tagach. Ta właściwość jest typu VisualStateGroupList:

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

        </VisualStateGroupList>
    </Setter>
</Style>

W tych tagach można uwzględnić jeden z większej VisualStateGroup liczby obiektów:

<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>

Pozostała część znaczników VSM jest taka sama jak poprzednio.

Oto strona VSM w stylu przedstawiająca kompletny znacznik VSM:

<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>

Teraz wszystkie Entry widoki na tej stronie odpowiadają w ten sam sposób na ich stany wizualizacji. Zwróć również uwagę, że stan "Ukierunkowane" zawiera teraz sekundę Setter , która daje każde Entry tło wapna również wtedy, gdy ma fokus wejściowy:

VsM w stylu

Stany wizualizacji w programie Xamarin.Forms

W poniższej tabeli wymieniono stany wizualizacji zdefiniowane w programie Xamarin.Forms:

Klasa Stany Więcej informacji
Button Pressed Stany wizualizacji przycisku
CheckBox IsChecked Stany wizualizacji CheckBox
CarouselView DefaultItem, , CurrentItem, , PreviousItemNextItem Stany wizualizacji CarouselView
ImageButton Pressed Stany wizualizacji ImageButton
RadioButton Checked, Unchecked Stany wizualizacji RadioButton
Switch On, Off Przełączanie stanów wizualizacji
VisualElement Normal, , Disabled, , FocusedSelected Wspólne stany

Dostęp do każdego z tych stanów można uzyskać za pośrednictwem grupy stanu wizualizacji o nazwie CommonStates.

Ponadto element CollectionView implementuje Selected stan . Aby uzyskać więcej informacji, zobacz Zmienianie koloru zaznaczonego elementu.

Ustawianie stanu na wielu elementach

W poprzednich przykładach stany wizualne zostały dołączone do pojedynczych elementów i działały na nich. Istnieje jednak również możliwość utworzenia stanów wizualizacji dołączonych do jednego elementu, ale ustawiania właściwości na innych elementach w tym samym zakresie. Pozwala to uniknąć konieczności powtarzania stanów wizualnych na każdym elemencie, na którym działają stany.

Typ Setter ma TargetName właściwość typu string, która reprezentuje element docelowy, Setter który będzie manipulować stanem wizualizacji. Po zdefiniowaniu TargetNameSetter właściwości ustawia Property element zdefiniowany w TargetName elemecie na Valuewartość :

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

W tym przykładzie Label nazwa label będzie miała właściwość TextColor ustawioną na Red. Podczas ustawiania TargetName właściwości należy określić pełną ścieżkę do właściwości w pliku Property. W związku z TextColor tym, aby ustawić właściwość w Labelobiekcie , Property jest określony jako Label.TextColor.

Uwaga

Każda właściwość, do którego Setter odwołuje się obiekt, musi być wspierana przez właściwość, którą można powiązać.

Na stronie Programu VSM ze stroną Setter TargetName w przykładzie pokazano, jak ustawić stan na wielu elementach z jednej grupy stanu wizualizacji. Plik XAML składa się z StackLayout elementu zawierającego Label element , Entryi 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>

Znaczniki VSM są dołączone do elementu StackLayout. Istnieją dwa wzajemnie wykluczające się stany o nazwach "Normal" i "Pressed" z każdym stanem zawierającym VisualState tagi.

Stan "Normalny" jest aktywny, gdy Button nie jest naciśnięty, a można wprowadzić odpowiedź na pytanie:

VsM Setter TargetName: normalny stan

Stan "Naciśnięty" staje się aktywny po naciśnięciu klawisza Button :

VsM Setter TargetName: Stan naciśnięcia

Wartość "Pressed" VisualState określa, że po naciśnięciu Button klawisza właściwość Scale zostanie zmieniona z wartości domyślnej 1 na 0,8. Ponadto nazwana Entryentry będzie miała swoją Text właściwość ustawioną na Paryż. W związku z tym wynik polega na tym, że po naciśnięciu Button przycisku zostanie ona ponownie przeskalowana, aby była nieco mniejsza, a Entry ekrany Paryż. Następnie, gdy Button element zostanie wydany, zostanie ponownie przeskalowany do wartości domyślnej 1, a Entry element wyświetla dowolny wcześniej wprowadzony tekst.

Ważne

Ścieżki właściwości nie są obecnie obsługiwane w Setter elementach określających TargetName właściwość.

Definiowanie własnych stanów wizualizacji

Każda klasa pochodząca z VisualElement klasy obsługuje typowe stany "Normal", "Focused" i "Disabled". Ponadto CollectionView klasa obsługuje stan "Selected". VisualElement Wewnętrznie klasa wykrywa, kiedy staje się włączona lub wyłączona, albo skoncentrowana lub nieskoncentrowana, i wywołuje metodę statycznąVisualStateManager.GoToState:

VisualStateManager.GoToState(this, "Focused");

Jest to jedyny kod programu Visual State Manager, który znajdziesz w VisualElement klasie . Ponieważ GoToState obiekt jest wywoływany dla każdego obiektu opartego na każdej klasie pochodzącej z VisualElementklasy , można użyć programu Visual State Manager z dowolnym VisualElement obiektem, aby reagować na te zmiany.

Co ciekawe, nazwa grupy stanu wizualizacji "CommonStates" nie jest jawnie przywoływana w pliku VisualElement. Nazwa grupy nie jest częścią interfejsu API programu Visual State Manager. W jednym z dwóch przykładowych programów pokazanych do tej pory można zmienić nazwę grupy z "CommonStates" na cokolwiek innego, a program nadal będzie działać. Nazwa grupy jest jedynie ogólnym opisem stanów w tej grupie. Niejawnie rozumie się, że stany wizualizacji w każdej grupie wzajemnie się wykluczają: jeden stan i tylko jeden stan jest bieżący w dowolnym momencie.

Jeśli chcesz zaimplementować własne stany wizualizacji, musisz wywołać VisualStateManager.GoToState kod. Najczęściej wykonasz to wywołanie z pliku za pomocą kodu klasy strony.

Na stronie Walidacja programu VSM w przykładzie pokazano, jak używać programu Visual State Manager w połączeniu z walidacją danych wejściowych. Plik XAML składa się z StackLayout dwóch elementów: Entry, i ButtonLabel :

<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>

Znaczniki VSM są dołączone do elementu StackLayout (o nazwie stackLayout). Istnieją dwa wzajemnie wykluczające się stany o nazwie "Valid" i "Invalid" z każdym stanem zawierającym VisualState tagi.

Jeśli parametr Entry nie zawiera prawidłowego numeru telefonu, bieżący stan to "Nieprawidłowy", a więc Entry ma różowe tło, drugi Label jest widoczny, a Button właściwość jest wyłączona:

Walidacja programu VSM: nieprawidłowy stan

Po wprowadzeniu prawidłowego numeru telefonu bieżący stan zmieni się na "Prawidłowy". Pobiera Entry tło wapna, drugi Label znika, a Button element jest teraz włączony:

Walidacja programu VSM: prawidłowy stan

Plik związany z kodem jest odpowiedzialny za obsługę TextChanged zdarzenia z pliku Entry. Procedura obsługi używa wyrażenia regularnego, aby określić, czy ciąg wejściowy jest prawidłowy, czy nie. Metoda w pliku za pomocą kodu o nazwie GoToState wywołuje metodę statyczną VisualStateManager.GoToState dla stackLayoutmetody :

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

Zwróć również uwagę, że GoToState metoda jest wywoływana z konstruktora w celu zainicjowania stanu. Zawsze powinien istnieć bieżący stan. Jednak nigdzie w kodzie nie ma żadnego odwołania do nazwy grupy stanu wizualizacji, chociaż jest on przywołyny w języku XAML jako "ValidationStates" na potrzeby jasności.

Zwróć uwagę, że plik związany z kodem musi uwzględniać tylko obiekt na stronie definiującej stany wizualizacji i wywołać VisualStateManager.GoToState ten obiekt. Dzieje się tak, ponieważ oba stany wizualizacji są obiektami docelowymi wielu obiektów na stronie.

Możesz się zastanawiać: jeśli plik związany z kodem musi odwoływać się do obiektu na stronie definiującej stany wizualizacji, dlaczego nie można bezpośrednio uzyskać dostępu do tego pliku i innych obiektów? To z pewnością może. Jednak zaletą korzystania z programu VSM jest możliwość kontrolowania sposobu, w jaki elementy wizualne reagują na inny stan w całości w języku XAML, co zapewnia cały projekt interfejsu użytkownika w jednej lokalizacji. Pozwala to uniknąć ustawiania wyglądu wizualizacji przez uzyskiwanie dostępu do elementów wizualnych bezpośrednio z tyłu kodu.

Wyzwalacze stanu wizualizacji

Stany wizualne obsługują wyzwalacze stanu, które są wyspecjalizowaną grupą wyzwalaczy definiujących warunki, w których VisualState należy zastosować.

Wyzwalacze stanu są dodawane do StateTriggers kolekcji elementu VisualState. Ta kolekcja może zawierać jeden wyzwalacz stanu lub wiele wyzwalaczy stanu. Element VisualState zostanie zastosowany, gdy wszystkie wyzwalacze stanu w kolekcji są aktywne.

W przypadku używania wyzwalaczy stanu do kontrolowania stanów wizualizacji użyj następujących reguł pierwszeństwa, aby określić, Xamarin.Forms który wyzwalacz (i odpowiadający VisualStateim ) będzie aktywny:

  1. Każdy wyzwalacz pochodzący z elementu StateTriggerBase.
  2. Aktywowano AdaptiveTrigger z powodu MinWindowWidth spełnienia warunku.
  3. Aktywowano AdaptiveTrigger z powodu MinWindowHeight spełnienia warunku.

Jeśli wiele wyzwalaczy jest jednocześnie aktywnych (na przykład dwa wyzwalacze niestandardowe), pierwszy wyzwalacz zadeklarowany w znaczniku ma pierwszeństwo.

Aby uzyskać więcej informacji na temat wyzwalaczy stanu, zobacz Wyzwalacze stanu.

Używanie programu Visual State Manager do adaptacyjnego układu

Xamarin.Forms Aplikacja uruchomiona na telefonie może być zwykle widoczna w proporcjach pionowych lub poziomych, a Xamarin.Forms program uruchomiony na pulpicie może mieć rozmiar, aby założyć wiele różnych rozmiarów i współczynników proporcji. Dobrze zaprojektowana aplikacja może wyświetlać zawartość w inny sposób dla różnych czynników formularzy stron lub okien.

Ta technika jest czasami znana jako układ adaptacyjny. Ponieważ układ adaptacyjny obejmuje wyłącznie wizualizacje programu, jest to idealna aplikacja programu Visual State Manager.

Prostym przykładem jest aplikacja, która wyświetla niewielką kolekcję przycisków, które wpływają na zawartość aplikacji. W trybie pionowym te przyciski mogą być wyświetlane w poziomie wiersza w górnej części strony:

Układ adaptacyjny programu VSM: pionowy

W trybie poziomym tablica przycisków może zostać przeniesiona na jedną stronę i wyświetlana w kolumnie:

Układ adaptacyjny programu VSM: poziome

Od góry do dołu program działa w platforma uniwersalna systemu Windows, Android i iOS.

Strona Układ adaptacyjny programu VSM w przykładzie definiuje grupę o nazwie "OrientationStates" z dwoma stanami wizualizacji o nazwach "Portret" i "Poziomo". (Bardziej złożone podejście może być oparte na kilku różnych szerokościach stron lub okien).

Znaczniki VSM występują w czterech miejscach w pliku XAML. Nazwana StackLayoutmainStack zawiera zarówno menu, jak i zawartość, która jest elementem Image . Powinno to StackLayout mieć orientację pionową w trybie pionowym i orientację poziomą w trybie poziomym:

<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>

Wewnętrzna ScrollView nazwana menuScroll i StackLayout nazwana menuStack implementują menu przycisków. Orientacja tych układów jest przeciwieństwem mainStack. Menu powinno być poziome w trybie pionowym i pionowym w trybie poziomym.

Czwarta sekcja znaczników VSM jest w niejawnym stylu dla samych przycisków. Ten znacznik ustawia VerticalOptionswłaściwości , HorizontalOptionsi Margin specyficzne dla orientacji pionowej i poziomej.

Plik związany z kodem ustawia BindingContext właściwość menuStack w celu zaimplementowania Button poleceń, a także dołącza program obsługi do SizeChanged zdarzenia strony:

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

Procedura SizeChanged obsługi wywołuje VisualStateManager.GoToState dwa StackLayout elementy i ScrollView , a następnie przechodzi przez elementy podrzędne menuStack elementu w celu wywołania VisualStateManager.GoToStateButton elementów.

Może się wydawać, że plik za kodem może obsługiwać zmiany orientacji bardziej bezpośrednio, ustawiając właściwości elementów w pliku XAML, ale program Visual State Manager jest zdecydowanie bardziej ustrukturyzowanym podejściem. Wszystkie wizualizacje są przechowywane w pliku XAML, gdzie stają się łatwiejsze do sprawdzania, konserwacji i modyfikowania.

Visual State Manager z platformą Xamarin.University

Xamarin.Forms 3.0 Visual State Manager wideo