WPF 文本淡出再淡入特效

6
我正在尝试使用WPF动画来创造一个效果,在文本属性中的数据发生变化时,文本会淡出,然后再淡入..或者更好的交叉淡入淡出效果。
我已经成功实现了其中一半的功能,下面的代码响应文本更改事件,立即使文本不可见,然后在3秒钟内淡入。
淡出文本同样简单,只需更改标签的From和To属性。但是问题在于屏幕上的文本立即更改。当然,这通常是绝对必要的,但在这种情况下,我希望旧文本淡出,然后新文本淡入。
在WPF动画中有没有什么聪明的技巧可以做到这一点?
当前未完成的触发器:
<Style TargetType="TextBlock" x:Key="fadeinout">
        <Style.Triggers>
            <EventTrigger RoutedEvent="Binding.TargetUpdated">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="0:0:3" From="0.0" To="1.0" BeginTime="0:0:0" />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Style.Triggers>
    </Style>
4个回答

4

我同意frances1983的观点。我的做法是创建一个新的UserControl,可以无缝地处理旧文本和新文本之间的淡入淡出效果。

我正在尝试类似的操作,我想让一个标签只显示几秒钟,然后消失。这是我的做法:

<Label  Name="lbl" DockPanel.Dock="Bottom" HorizontalAlignment="Center" Visibility="Collapsed">
    <Label.Style>
        <Style TargetType="{x:Type Label}">
            <Style.Triggers>
                <Trigger Property="Visibility" Value="Visible">
                    <Trigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="00:00:00" BeginTime="00:00:00" From="0.0" To="1.0" />
                                <DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="00:00:03" BeginTime="00:00:02" From="1.0" To="0.0" />
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.EnterActions>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Label.Style>
    Display Text
</Label>

然后,在标签文本更改的代码中:

//Make the label visible, starting the storyboard.
lbl.Visibility = Visibility.Visible;

DispatcherTimer t = new DispatcherTimer();
//Set the timer interval to the length of the animation.
t.Interval = new TimeSpan(0, 0, 5);
t.Tick += (EventHandler)delegate(object snd, EventArgs ea)
{
    // The animation will be over now, collapse the label.
    lbl.Visibility = Visibility.Collapsed;
    // Get rid of the timer.
    ((DispatcherTimer)snd).Stop();
};
t.Start();

您可以轻松地将此示例修改为UserControl。只需更改Visibility == Hidden上的淡出效果,添加一个Storyboard来执行Visibility == Visible的相反操作,并在Tick处理程序中更改文本并重置可见性即可。

希望这能有所帮助!


2

这里提供一种自动实现淡出、切换值、淡入的方法。

使用方法(在设置正确的命名空间 xmlns:l 后):

Label l:AnimatedSwitch.Property="Content" l:AnimatedSwitch.Binding="{Binding SomeProp}"/>

代码(这是概念验证代码,没有错误处理,不适用于生产环境)。
public class AnimatedSwitch : DependencyObject
{
    // Define the attached properties

    public static DependencyProperty BindingProperty =
        DependencyProperty.RegisterAttached("Binding", typeof(object), typeof(AnimatedSwitch),
        new PropertyMetadata(BindingChanged));
    public static DependencyProperty PropertyProperty =
        DependencyProperty.RegisterAttached("Property", typeof(string), typeof(AnimatedSwitch));
    public static object GetBinding(DependencyObject e)
    {
        return e.GetValue(BindingProperty);
    }
    public static void SetBinding(DependencyObject e, object value)
    {
        e.SetValue(BindingProperty, value);
    }
    public static string GetProperty(DependencyObject e)
    {
        return (string)e.GetValue(PropertyProperty);
    }
    public static void SetProperty(DependencyObject e, string value)
    {
        e.SetValue(PropertyProperty, value);
    }

    // When the value changes do the fadeout-switch-fadein

    private static void BindingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Storyboard fadeout = new Storyboard();
        var fadeoutAnim = new DoubleAnimation(){To=0,Duration=new Duration(TimeSpan.FromSeconds(0.3))};
        Storyboard.SetTarget(fadeoutAnim,d);
        Storyboard.SetTargetProperty(fadeoutAnim, new PropertyPath("Opacity"));
        fadeout.Children.Add(fadeoutAnim);
        fadeout.Completed += (d1, d2) =>
            {
                d.GetType().GetProperty(GetProperty(d)).SetValue(d, GetBinding(d), null);

                Storyboard fadein = new Storyboard();
                var fadeinAnim = new DoubleAnimation() { To = 1, Duration = new Duration(TimeSpan.FromSeconds(0.3)) };
                Storyboard.SetTarget(fadeinAnim, d);
                Storyboard.SetTargetProperty(fadeinAnim, new PropertyPath("Opacity"));
                fadein.Children.Add(fadeinAnim);
                fadein.Begin();
            };
        fadeout.Begin();
    }
}

1
这项任务的最佳解决方案是使用“过渡Presenter”。Transition Presenter是一个容器,用于包含您的控件(可以是TextBlock或其他任何控件),它通过应用所分配的过渡来响应内容的更改。您可以选择预定义的过渡之一或创建自己的过渡(使用XAML)。通常,过渡Presenter使用数据模板显示绑定的数据。最基本的示例如下:
<lib:TransitionPresenter Transition="{StaticResource FadeTransition}
    Content="{Binding MyValue}">
    <lib:TransitionPresenter.Resources>
        <DataTemplate DataType="{x:Type System:string}">
            <TextBlock Text={Binding}/>
        </DataTemplate>
    </lib:TransitionPresenter.Resources>
</lib:TransitionPresenter>

这里有两个包含源代码的库,实现了过渡演示功能:

-2

我认为这在仅使用XAML的解决方案中不可能实现。TextBlock只知道文本,而不知道“旧”和“新”的文本。

我会创建一个从TextBlock派生的自定义控件,并在TargetUpdated事件上执行以下操作:

  • 调用“淡出”故事板
  • 更改文本
  • 调用“淡入”故事板

祝你好运 :)


肯定是可能的,只需要使用两个文本块。 - Mauro Sampietro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接