Анимация между визуальными состояниями без взрыва определенных переходов

У меня есть довольно простой сценарий, который я пытаюсь реализовать в Silverlight, но, несмотря на всю невероятно мощную функциональность переходов в Silverlight / Blend 4, я просто не могу понять, как это сделать.

У меня есть макет, который сводится к следующему:

<UserControl>
    <Grid>
        <StackPanel>
            <Button x:Name="Button1" />
            <Button x:Name="Button2" />
            <Button x:Name="Button3" />
            <Button x:Name="Button4" />
        </StackPanel>
        <Grid x:Name="Page1" />
        <Grid x:Name="Page2" />
        <Grid x:Name="Page3" />
        <Grid x:Name="Page4" />
    </Grid>
</UserControl>

Сначала все четыре сетки страниц скрыты и масштабируются до нулевого размера, но когда вы нажимаете соответствующую кнопку, страница должна отображаться с растущей анимацией. При нажатии другой кнопки предыдущая страница должна исчезнуть с уменьшающейся анимацией, а другая страница должна появиться с растущей анимацией. Таким образом, вы можете использовать кнопки для перехода между всеми четырьмя страницами.

Из того, что я прочитал, «правильный» способ сделать это - использовать визуальные состояния в пользовательском элементе управления. Итак, я создал четыре состояния, от Page1 до Page4, и для каждого состояния установил соответствующую сетку страниц для отображения. Затем я помещаю команды на кнопки, чтобы изменить визуальное состояние пользовательского элемента управления. Это работало нормально, и я мог переключаться между страницами, но когда я начал пытаться определять анимацию между состояниями, у меня возникли проблемы.

Сначала я подумал, что могу определить анимацию «Кому *» и «От *» для каждого состояния. Итак, когда вы были в состоянии Page1 и нажали кнопку, чтобы перейти в состояние Page2, он воспроизвел бы анимацию «От *», скрывающую страницу 1, а затем анимацию «Кому *», отображающую страницу 2. Но это не работает. Даже если вы определили анимацию «Кому *» и «От *» для каждого состояния, Silverlight воспроизводит только анимацию «Кому *» и полностью игнорирует анимацию «От *»!

Хуже того, похоже, что Silverlight и должен работать именно так, хотя в этом нет никакого смысла! Это означает, что если я хочу, чтобы каждая страница сжималась, а затем на ее месте росла другая страница, мне пришлось бы определять отдельный переход от каждого состояния к другому состоянию! Для моих текущих четырех страниц это означало бы двенадцать отдельных переходов, но когда я хочу увеличить количество страниц, это число будет расти. На десять страниц потребуется 9 * 9 = 81 переход! Все для того, чтобы текущая страница уменьшилась, а новая - увеличилась.

Я не могу поверить, что нет лучшего способа справиться с таким простым сценарием, но я не могу найти ничего, чтобы сказать, как это сделать. Я мог бы, вероятно, взломать его вместе, используя программную часть, которая изменяет раскадровки, но я хочу разрешить просмотр и редактирование сеток страниц в Blend, а также все, что я читаю, говорит, чтобы избежать использования скрытого кода и использовать модели просмотра и визуальные состояния для обработки вещей

Скажите, пожалуйста, мне не хватает чего-то очевидного?


person Jon Rimmer    schedule 02.03.2011    source источник


Ответы (1)


В Blend вы просто щелкаете состояние на вкладке «Состояния», чтобы начать запись состояния, определяете, как должно выглядеть состояние, и устанавливаете продолжительность перехода между состояниями.

Вам не нужно беспокоиться о каждой индивидуальной перестановке перехода между состояниями, если только вы не хотите, чтобы каждая из них отличалась.

Если в ваших состояниях используются свойства, которые не могут быть «линейно» анимированы (например, изменение видимости), проверьте кнопку FluidLayout.

Изменить: вы можете создать эффект «полного сжатия, а затем увеличения», который вы описываете, используя только одну дополнительную раскадровку для каждого состояния - переход Any -> {State}, задав для BeginTime задержку перед увеличением текущего элемента.

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
mc:Ignorable="d"
x:Class="CommandingLeakWithScrollbar.UserControl1"
d:DesignWidth="640" d:DesignHeight="480">

<Grid x:Name="LayoutRoot">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="VisualStateGroup">
            <VisualStateGroup.Transitions>
                <VisualTransition GeneratedDuration="0:0:1"/>
                <VisualTransition GeneratedDuration="0:0:1" To="Page1">
                    <Storyboard>
                        <DoubleAnimation BeginTime="0:0:1" Duration="0:0:1" To="640" Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="grid1" d:IsOptimized="True" />
                        <DoubleAnimation BeginTime="0:0:1" Duration="0:0:1" To="480" Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="grid1" d:IsOptimized="True"/>
                    </Storyboard>
                </VisualTransition>
                <VisualTransition GeneratedDuration="0:0:1" To="Page2">
                    <Storyboard>
                        <DoubleAnimation BeginTime="0:0:1" Duration="0:0:1" To="640" Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="grid2" d:IsOptimized="True" />
                        <DoubleAnimation BeginTime="0:0:1" Duration="0:0:1" To="480" Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="grid2" d:IsOptimized="True"/>
                    </Storyboard>
                </VisualTransition>
                <VisualTransition From="None" GeneratedDuration="0:0:1" To="Page1"/>
                <VisualTransition From="None" GeneratedDuration="0:0:1" To="Page2"/>
            </VisualStateGroup.Transitions>
            <VisualState x:Name="None"/>
            <VisualState x:Name="Page1">
                <Storyboard>
                    <DoubleAnimation Duration="0" To="640" Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="grid1" d:IsOptimized="True" />
                    <DoubleAnimation Duration="0" To="480" Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="grid1" d:IsOptimized="True" />
                </Storyboard>
            </VisualState>
            <VisualState x:Name="Page2">
                <Storyboard>
                    <DoubleAnimation Duration="0" To="640" Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="grid2" d:IsOptimized="True"/>
                    <DoubleAnimation Duration="0" To="480" Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="grid2" d:IsOptimized="True"/>
                </Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <Grid x:Name="grid1"  Background="Beige" Width="40" Height="40" HorizontalAlignment="Left" VerticalAlignment="Top"/>
    <Grid x:Name="grid2" HorizontalAlignment="Right" Width="40" Height="40" VerticalAlignment="Top" Background="Wheat" />
    <Grid HorizontalAlignment="Left" Width="40" Height="40" VerticalAlignment="Bottom" />
    <Grid HorizontalAlignment="Right" Width="40" Height="40" VerticalAlignment="Bottom"/>
    <StackPanel HorizontalAlignment="Center">
        <Button Content="Reset" >
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ei:GoToStateAction StateName="None"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
        <Button Content="Page1" >
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ei:GoToStateAction StateName="Page1"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
        <Button Content="Page2" >
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ei:GoToStateAction StateName="Page2"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </StackPanel>
</Grid>

person foson    schedule 02.03.2011
comment
Да, я пробовал это, но, к сожалению, для сгенерированных переходов Silverlight начинает переносить все свойства одновременно. Мне нужно, чтобы видимая панель уменьшилась до нуля, масштабируя ее преобразования X и Y до нуля, а ЗАТЕМ, чтобы новая панель отображалась в обратном порядке. - person Jon Rimmer; 03.03.2011
comment
Ага! Это работает, спасибо вам большое! Сначала у меня были небольшие проблемы, потому что я устанавливал видимость как свернутую для каждой сетки, а также ее постепенное исчезновение, но сгенерированный переход применяет изменение немедленно, так что вы не видите, что он сокращается. Если я оставлю его видимым, но уменьшу и с нулевой непрозрачностью, все будет хорошо. Еще раз спасибо! - person Jon Rimmer; 03.03.2011