Как установить анимацию WPF BeginTime на основе свойств (Top / Tabstop) элемента управления - PullRequest
3 голосов
/ 16 июля 2011

У меня есть приложение WPF, которое имеет ряд кнопок на вертикальной панели стека, подобно тому, как будет выглядеть меню DVR.Я выяснил, как сделать анимацию, при которой при загрузке каждой новой страницы меню кнопки / элементы управления все {не исчезают, падают, растекаются и т. Д.} Существуют, что приятно, но слишком равномерно.Что мне действительно нравится, так это чтобы анимация запускалась на каждой кнопке в несколько разное время, в зависимости от ее местоположения или свойств табуляции.Так, например, первая кнопка должна начинаться первой, затем следующей и т. Д. До нижней кнопки, возможно, задержка 50 мс между каждым запуском (но такая, что первая не должна заканчиваться раньше 2-й).начинается).Конечно, я мог бы просто сделать разные анимации для каждой кнопки, но я надеюсь на более элегантное решение.Я не вижу способа загрузить какие-либо свойства элемента управления в BeginTime раскадровки.Есть ли хороший способ использовать только XAML, или для чего-то подобного потребуется код?Если последнее, возможно ли упаковать это в Поведение и быть в состоянии загрузить это декларативно позже, или я застрял с императивным кодом навсегда?

1 Ответ

8 голосов
/ 18 июля 2011

Короткий ответ - нет (насколько мне известно), вы не можете точно сделать то, что вы спрашиваете только с XAML, и вот почему.

Хотя в WPF есть много способов создания анимации, единственный способ анимировать с помощью XAML - это использовать раскадровки. Единственный способ поделиться раскадровкой между элементами - это упаковать его в такой ресурс, как Style, ControlTemplate или DataTemplate. Однако, чтобы использовать раскадровку в качестве ресурса, он должен быть Freezable, что означает, что он не может содержать никаких выражений привязки данных, которые потребовались бы для связи анимации BeginTime со свойством цели анимации (например, TabIndex или какой-либо другой). другое свойство ваших кнопок). Даже если бы вы могли как-то связать BeginTime анимации со свойством Button, вам все равно нужно будет использовать codebehind, чтобы написать ValueConverter для преобразования значения свойства Button в значение TimeSpan (желаемая совокупная задержка в 50 мс).

Таким образом, чтобы сделать в точности , что вы хотите, вам нужно использовать codebehind, как показано в этом примере:

XAML:

<StackPanel HorizontalAlignment="Left" Width="100" Loaded="StackPanel_Loaded">
    <Button Content="Button1"/>
    <Button Content="Button2"/>
    <Button Content="Button3"/>
    <Button Content="Button4"/>
    <Button Content="Button5"/>
    <Button Content="Button6"/>
    <Button Content="Button7"/>
    <Button Content="Button8"/>
    <Button Content="Button9"/>
    <Button Content="Button10"/>
</StackPanel>

Codebehind:

private void StackPanel_Loaded(object sender, RoutedEventArgs e)
{
    StackPanel stackPanel = sender as StackPanel;
    DoubleAnimation fadeInAnimation = new DoubleAnimation(1.0, new Duration(TimeSpan.FromMilliseconds(200)));
    for (int i = 0; i < stackPanel.Children.Count; i++)
    {
        fadeInAnimation.BeginTime = TimeSpan.FromMilliseconds(i * 50);
        stackPanel.Children[i].Opacity = 0.0;
        stackPanel.Children[i].BeginAnimation(UIElement.OpacityProperty, (AnimationTimeline)fadeInAnimation.GetAsFrozen());
    }
}

При этом существуют способы приблизить желаемое поведение, используя только XAML. Например, вы можете наложить StackPanel с помощью LinearGradientBrush OpacityMask и анимировать его с помощью одной раскадровки, например:

XAML:

<StackPanel HorizontalAlignment="Left" Width="100">
    <StackPanel.OpacityMask>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
            <GradientStop Color="Black"/>
            <GradientStop x:Name="TransparentGradient" Color="Transparent"/>
        </LinearGradientBrush>
    </StackPanel.OpacityMask>
    <StackPanel.Triggers>
        <EventTrigger RoutedEvent="Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation
                        Storyboard.TargetName="TransparentGradient" Storyboard.TargetProperty="Offset"
                        To="1.0" Duration="0:0:0.5"/>
                    <ColorAnimation
                        Storyboard.TargetName="TransparentGradient" Storyboard.TargetProperty="Color"
                        To="Black" BeginTime="0:0:0.5" Duration="0:0:0.5"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </StackPanel.Triggers>
    <Button Content="Button1"/>
    <Button Content="Button2"/>
    <Button Content="Button3"/>
    <Button Content="Button4"/>
    <Button Content="Button5"/>
    <Button Content="Button6"/>
    <Button Content="Button7"/>
    <Button Content="Button8"/>
    <Button Content="Button9"/>
    <Button Content="Button10"/>
</StackPanel>

Это дало бы вам хороший эффект сверху донизу. Другие эффекты также могут быть возможны при небольшом творческом подходе, но совет: старайтесь не тратить слишком много времени на поиск сложных решений XAML, когда вы можете добиться желаемого эффекта. всего несколько строк кода.

Удачного кодирования!

...