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?
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).