Úskalí třídy VisualStateManager

Visual Studio Development WinUI XAML

7 years ago

VisualStateManager je velmi užitečný při sestavování XAML designu. Spolu s AdaptiveTriggery v UWP umožňuje snadno přecházet mezi jednotlivými stavy rozložení tak, aby aplikace vypadala skvěle na každém displeji. Měli bychom si však dát pozor na dva nenápadné problémy, na které v souvislosti s touto třídou můžeme narazit.

Chyták 1: Umístění VisualStateMangeru

Vezměme následující úryvek kódu:

<UserControl ...>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState>
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="700" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="TargetText.Text" Value="This is never applied :-(" />
                    <Setter Target="Button.Background" Value="Red" />
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <Button x:Name="Button">
        <TextBlock x:Name="TargetText" Text="VisualStateManager in root" />
    </Button>
</UserControl>

Pokud tento kód zkusíte použít, zjistíte, že stav není nikdy aktivován (text u elementu TextBlock se nezmění, když je okno širší než 700 obrazových bodů). Důvodem je fakt, že VisualStateManager nemůže být připojen k hlavnímu elementu XAML layoutu (Page , UserControl , ...), ale musí být uvnitř nějakého ovladacího prvku nebo panelu. Nejčastěji se VisualStateManager umisťuje do hlavního Content UI elementu:

<UserControl ...>
    <Button>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup>
                <VisualState>
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="700" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="TargetText.Text" Value="Adaptive trigger applied!" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <TextBlock x:Name="TargetText" Text="VisualStateManager inside root Grid" />
    </Button>
</UserControl>

Chyták 2: Neplatné settery

Uvažujme následující kód:

<UserControl ...>
    <Button>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup>
                <VisualState>
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="700" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="TargetText.Text" Value="This is never applied because the other Setter has invalid syntax" />
                        <Setter Target="TargetText.Foregroun" Value="Red" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <TextBlock x:Name="TargetText" Text="VisualStateManager with invalid setter" Foreground="Black" />
    </Button>
</UserControl>

Na první pohled vypadá vše v pořádku. Na druhý ale zjistíme, že druhý setter obsahuje nevinnou chybu v Targetu Setteru pro TargetText.Foreground. Pravděpodobně očekáváte, že tento problém se projeví nejpozději za běhu aplikace jako výjimka. Překvapivě tomu tak ale není. Když Target nebo Value kteréhokoliv Setteru nejsou platné, aplikace i přesto poběží bez výjimek, ale daný VisualState obsahující tento Setter nebude nikdy aplikován. V tomto konkrétním případě nebude nastavena ani vlastnost Foreground ani vlastnost Text . Kdykoliv narazíte na VisualState , který se zdá nefunkční, zkontrolujte pro jistotu, zda všechny Settery jsou skutečně správně. Můžete také zkusit zakomentovat celý blok Setters a poté postupně jeden po druhém odkomentovávat, dokud nedorazíte na viníka.

Zdrojový kód

Zdrojový kód pro tento příspěvek najdete na mém GitHubu.

Summary

VisualStateManager je velmi užitečný a výrazně zjednodušuje vytváření komplexního adaptivního designu. Musíme však dát pozor, abychom jej používali správně, alespoň do té doby než Visual Studio XAML editor dostane podporu IntelliSense pro Target and Value u Setterů .