WPF: Using Storyboards in Custom Control - CSharp

This is a discussion on WPF: Using Storyboards in Custom Control - CSharp ; Hello All, I have defined a custom control (call it CustomButton). One thing that I would like to put into this custom control is a color animation (in its ContentTemplate). However, I would like to be able to specify the ...

+ Reply to Thread
Results 1 to 2 of 2

WPF: Using Storyboards in Custom Control

  1. Default WPF: Using Storyboards in Custom Control

    Hello All,

    I have defined a custom control (call it CustomButton).

    One thing that I would like to put into this custom control is a color
    animation (in its ContentTemplate). However, I would like to be able to
    specify the Color in this animation via binding.

    Poking around, I found this post
    (http://forums.msdn.microsoft.com/en-...-a50ab1a64ba5/)
    that seems to say that it cannot be done (I do get the exception thrown as
    described in the article). Does anybody have a workaround that allows for a
    bindable property?

    Thanks,
    WtS

  2. Default RE: WPF: Using Storyboards in Custom Control

    Hi Wonko,

    Unfortunately, this is a by-design "feature" of WPF, Styles and Templates
    could be used in multiple referencing points (for instance, when you define
    a Button style, these styles will be used by multiple Button instances
    residing across the visual tree), and those referencing points will
    potentially be created by different threads. So in order to make them
    thread safe when used across threading boundaries, Styles and Templates
    will be sealed, if you use reflector to examine the Style and
    FrameworkTemplate class definition, you will find that both Style and
    FrameworkTemplate classes all implement ISealable internal interface, this
    interface imposes the sealable contract, which means that when a Style or
    Template is sealed, it will be made read-only, read-only objects could be
    used safely across threading boundaries, and any Freezable objects within
    the Style and Template definition will also be frozen (because Freezable
    objects take freezing semantic), this is expected, since when you want to
    make an object read-only, you need to make sure that any objects which this
    object has reference to should also be made read-only. The caveat here is
    that Freezable objects when have data binding or dynamic resource
    referencing (via DynamicResourceExtension) set on it cannot be frozen,
    because data binding or dynamic resource referencing relies on the specific
    contextual information to make it work (thinking of RelativeSource and
    ElementName data binding), and if WPF allows you to set data binding on
    frozen Freezable objects, those Freezable objects could be used and
    attached to multiple parenting points (to make the matter worse, those
    parenting points could reside in different threads), which could confuse
    the RelativeSource and ElementName data binding, and potentially cause some
    nasty threading issues.

    So in order to work around this limitation, you could choose not to
    introduce any Freezable objects inside Styles or Templates; you could place
    the Storyboard/TimelineAnimation inside the theme resource dictionary as
    follows:

    <SolidColorBrush x:Key="brush" Color="Green"/>
    <!--Note that in order to refer to theme resources, you need to use
    ComponentResourceKey.
    And you also need to specify the x:Shared attribute to false to
    prevent resource sharing, this could effectively workaround
    the limiation that Freezable resources will be frozen by the theme
    dictionary loading code-->

    <ColorAnimation
    x:Key="{ComponentResourceKey ResourceId=ColorAnimation,
    TypeInTargetAssembly={x:Type local:CustomButton}}"
    x:Shared="False"
    To="{Binding Path=Color, Source={StaticResource brush}}"
    Duration="0:0:2" RepeatBehavior="Forever"/>
    <Style TargetType="{x:Type local:CustomButton}">
    <Setter Property="Template">
    <Setter.Value>
    <ControlTemplate>
    <TextBlock Text="CustomButton" Tag="Green" x:Name="textBlock">
    <TextBlock.Background>
    <SolidColorBrush x:Name="back" Color="Red"/>
    </TextBlock.Background>
    </TextBlock>
    </ControlTemplate>
    </Setter.Value>
    </Setter>
    </Style>

    And inside the CustomButton control implementation, you could override the
    OnApplyTemplate() protected method as follows:

    public override void OnApplyTemplate()
    {
    base.OnApplyTemplate();
    //Presumably you could use FrameworkElement.FindResource() or
    FrameworkElement.TryFindResource() to look up the "ColorAnimation"
    resource,
    //unforunately those two APIs will freeze resource before returning it
    for your //disposal. That's why I use the SetResourceReference hack here.
    this.SetResourceReference(Button.TagProperty, new
    ComponentResourceKey(typeof(CustomButton), "ColorAnimation"));

    SolidColorBrush solidColorBrush = this.GetTemplateChild("back") as
    SolidColorBrush;
    this.MouseEnter += delegate
    {
    ColorAnimation colorAnimation = this.Tag as ColorAnimation;
    if (colorAnimation != null && solidColorBrush != null)
    {
    Console.WriteLine(colorAnimation.IsFrozen);
    solidColorBrush.BeginAnimation(SolidColorBrush.ColorProperty,
    colorAnimation);
    }
    };
    }

    The above method looks like a little bit like a hackery, so I recommend you
    to construct Animations and Storyboards completely at the code behind
    (presumably inside the instance constructor of CustomButton class (note
    that per instance Freezable objects are thread safe because WPF imposes the
    dispatcher threading model for Freezable objects), then you could hook up
    to the any events such as MouseEnter/MouseLeave to start and stop those
    Animations and Storyboards.

    --------------------------------------------------
    Best regards,
    Macro Zhou (v-mazho@online.microsoft.com, remove 'online.')
    Microsoft Online Community Support

    Delighting our customers is our #1 priority. We welcome your comments and
    suggestions about how we can improve the support we provide to you. Please
    feel free to let my manager know what you think of the level of service
    provided. You can send feedback directly to my manager at:
    msdnmg@microsoft.com.

    This posting is provided "AS IS" with no warranties, and confers no rights.


+ Reply to Thread