在控制模板资源中挂钩故事板的完成事件

本文关键字:故事 事件 控制 资源 | 更新日期: 2023-09-27 18:08:06

我正在创建一个自定义控件ImageFader。样式模板看起来像这样:

<ControlTemplate TargetType="{x:Type controls:ImageFader}">
    <Grid>
        <Image HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                Stretch="{TemplateBinding Stretch}"
                x:Name="PART_SourceImage" Opacity="1" />
        <Image HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                Stretch="{TemplateBinding Stretch}"
                x:Name="PART_TargetImage" Opacity="0" />
    </Grid>
    <ControlTemplate.Resources>
        <Storyboard x:Key="FadeImageStoryboard">
            <!-- fade in the new image -->
            <DoubleAnimation From="0" To="1"
                                Duration="{TemplateBinding FadeTime}"
                                Storyboard.TargetName="PART_TargetImage"
                                Storyboard.TargetProperty="Opacity" />
            <!-- fade out the previous image -->
            <DoubleAnimation From="1" To="0"
                                Duration="{TemplateBinding FadeTime}"
                                Storyboard.TargetName="PART_SourceImage"
                                Storyboard.TargetProperty="Opacity" />
        </Storyboard>
    </ControlTemplate.Resources>
</ControlTemplate>

在代码中,我有这样的:

public override void OnApplyTemplate()
{
    base.OnApplyTemplate();
    SourceImage = Template.FindName("PART_SourceImage", this) as Image;
    TargetImage = Template.FindName("PART_TargetImage", this) as Image;
    FadeImageStoryboard = Template.Resources["FadeImageStoryboard"] as Storyboard;
    FadeImageStoryboard.Completed += new EventHandler(FadeImageStoryboard_Completed);
}

在完成的处理程序中,我试图交换图像并重置其不透明度:

private void FadeImageStoryboard_Completed(object sender, EventArgs e)
{
    SourceImage.Source = TargetImage.Source;
    SourceImage.Opacity = 1;
    TargetImage.Opacity = 0;
}

我在DispatchTimer中使用如下方式开始动画:

FadeImageStoryboard.Begin(this, this.Template, true);

一切都很好,直到我把两个或更多的ImageFader控件在同一个窗口。当我这样做时(使用DispatchTimer以不同的间隔开始动画),故事板完成事件为两个imagefader运行。

我相信我的控件正在从模板资源中获取故事板作为静态引用。

如何避免这种情况?

在控制模板资源中挂钩故事板的完成事件

一个解决方案可以从代码中创建故事板,它不会变得太丑:)

只需更改下面的代码:

public override void OnApplyTemplate()
{
    base.OnApplyTemplate();
    SourceImage = Template.FindName("PART_SourceImage", this) as Image;
    TargetImage = Template.FindName("PART_TargetImage", this) as Image;
    FadeImageStoryboard = GetFadeImageStoryboard();
    FadeImageStoryboard.Completed += new EventHandler(FadeImageStoryboard_Completed);
}
private Storyboard GetFadeImageStoryboard()
{
    DoubleAnimation fadeNewImage = new DoubleAnimation { From = 0, To = 1, Duration = FadeTime };
    Storyboard.SetTarget(fadeNewImage, SourceImage);
    Storyboard.SetTargetProperty(fadeNewImage, new PropertyPath("Opacity"));
    DoubleAnimation fadePreviousImage = new DoubleAnimation { From = 0, To = 1, Duration = FadeTime };
    Storyboard.SetTarget(fadePreviousImage, TargetImage);
    Storyboard.SetTargetProperty(fadePreviousImage, new PropertyPath("Opacity"));
    Storyboard fadeImageStoryboard = new Storyboard();
    fadeImageStoryboard.Children.Add(fadeNewImage);
    fadeImageStoryboard.Children.Add(fadePreviousImage);
    return fadeImageStoryboard;
}

每个控件都会得到它自己的Storyboard。我不认为把这些故事板作为模板的一部分是一个好主意,因为它们是这个控件正确行为的重要组成部分,而且也没有太多的东西要改变(所以在几乎所有的模板中代码都必须重复)。