在控制模板资源中挂钩 Storyboard 的已完成事件时出现问题
我正在创建一个名为 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 运行。
我相信我的控制是从模板资源中获取故事板作为静态参考。
我该如何避免这种情况?
I'm creating a custom control called ImageFader. The style template looks like this:
<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>
In the code, I have this:
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);
}
In the completed handler I'm trying to swap the images and reset their opacity:
private void FadeImageStoryboard_Completed(object sender, EventArgs e)
{
SourceImage.Source = TargetImage.Source;
SourceImage.Opacity = 1;
TargetImage.Opacity = 0;
}
I start the animation inside of a DispatchTimer using this:
FadeImageStoryboard.Begin(this, this.Template, true);
Everything works well until I place two or more ImageFader controls on the same window. When I do that (with a DispatchTimer starting the animation at different intervals) the storyboard completed event runs for both ImageFaders.
I believe my control is getting the storyboard from the template resources as a static reference.
How do I avoid this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
一种解决方案可能是从代码创建故事板,它不会变得太难看:)
只需更改此代码:
每个控件都会获得它自己的故事板。我不认为将这些故事板作为模板的一部分是一个好主意,因为它们是此控件正确行为的重要组成部分,而且它们上没有太多需要更改的内容(因此几乎所有情况下)模板代码必须重复)。
One solution could be creating the Storyboards from code, it doesn't gets too ugly :)
Just change your code for this one:
And every control will get it's own Storyboard. I don't think that making these storyboards as part of the templates is a good idea, as they are an esencial part in the correct behaviour of this control, and also there are not too many thing to change on them (so in almost all the templates the code would have to be repeated).