Posts tagged ‘Custom Control’

How To Animate a Changing Property in a Custom Control in Silverlight

For my recent visualization, I created a custom control in Silverlight that animated the color of a Path every time a “Fill” property on the control was changed. I thought I would pass along my learning from this process.

First thing I learned was that you cannot use TemplateBinding in a Storyboard (I think). I asked this question on Stack Overflow and I haven’t gotten an answer. But I’m pretty sure that in Silverlight you cannot use TemplateBinding to attach a property to a KeyFrame value. This means that you have to have a pointer in the control code the allows access to the KeyFrame so you can update the value.

I’ll walk through the conceptual part of animating a property in a Custom Control in Sivlerlight and then walk through the code to it.

Step 1: Create a PART to your control to hold the Storyboard and a PART to hold the KeyFrame you want to manipulate

I cover how to make a PART to your control here because it was too much to put into a single blog post. You’re going to want to make your Storyboard a PART that is accessed via resources (via MyControlName.Resources[MyStoryboardName]) and your KeyFrame should be a PART that is accessed the normal way (via the GetTemplateChild(MyKeyFrameName) method).

Step 2: Create the DependencyProperty you want to drive the animation

Yet another chance for me to endlessly flog Robby Ingebretsen’s awesome Silverlight Code Snippets. If you use these, use ‘sldpc’, which is the DependencyProperty with a property changed callback. We want to manually fire the animation when the property changes, so we’re going to do that in the callback.

If you don’t want to use Robby’s stuff, here’s the code for a DependencyProperty with a property changed callback. Because my visualization animates the color, I called my property “Fill”.

public SolidColorBrush Fill
{
    get { return (SolidColorBrush)GetValue(FillProperty); }
    set { SetValue(FillProperty, value); }
}

public static readonly DependencyProperty FillProperty =
    DependencyProperty.Register("Fill", typeof(SolidColorBrush), typeof(County),
    new PropertyMetadata(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), new PropertyChangedCallback(OnFillChanged)));

Step 3: Hook up a property changed callback and run the animation

Then, all you need to do is go into the property changed callback that you have created and assign your the new valie of the property to the keyframe value of the animation you want to run. Then run the animation.

private static void OnFillChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    MyControlType thisControl = d as MyControlType;
    if ((thisControl != null) && (thisControl._myStoryboard != null))
    {
        SolidColorBrush newBrushHolder = (SolidColorBrush)e.NewValue;

        thisCounty._myKeyFrame.Value = newBrushHolder.Color;
        thisCounty._myStoryboard.Begin();
    }
}

And now every time you change that value in the control, it will animate to the new value. Simple as that.

How To Create a PART in Your Silverlight Custom Control

There are about a dozen videos and tutorials on how to create a custom control in Silverlight 3. (Here’s my favorite, from Karen Corby. Skip to about 47 minutes for the tutorial part.)

But sometimes, you (and by “you”, I mean me) need help figuring out how to create a PART for a control because, let’s be honest, you don’t do it all the time and no one has a blog post on just this little part of control building.

If you’re wondering what a PART is, here’s a short explanation: A PART is a naming convention that allows a control (code) to make a contract with the control template (XAML) in Silverlight. The control says to the template, “I’m going to be doing something programmatic with this part, so it better be there”. The template responds, “Here’s that part you wanted.”

I not actually talking down to anyone, this is really how my brain works.

There are basically five steps in creating a PART. I think you can actually do it in less, but I’m trying to follow what I think is proper coding practice. In this tutorial, we’re going create parts out of a Button and also a Storyboard (partly because there are different ways to assign a PART if it is in located in the control resources like a Storyboard is).

Step 1: Define the control template parts you’ll need

Outside of the control class we need to add the TemplatePart attributes. Inside the class, we need to define the names of the UI objects we’re going to turn into parts as well as create some corresponding objects in the control so we can access those PARTs.

[TemplatePart(Name = MyControl.StoryboardString, Type = typeof(Storyboard))]
[TemplatePart(Name = MyControl.RootElementString, Type = typeof(FrameworkElement))]
[TemplatePart(Name = MyControl.ButtonString, Type = typeof(Button))]

public class MyControl : Control
{
    private const string StoryboardString = "PART_MyStoryboard";
    private const string RootElementString = "PART_RootElement"
    private const string ButtonString = "PART_MyButton";

    private Storyboard _targetStoryboard;
    private FrameworkElement _rootElement;
    private Button _targetButton;

What we’re going to do here is remarkably stupid because I don’t have the creativity right now to do something cool. When we press the button, we’ll play the storyboard. We need the RootElement because… you’ll see in a moment.

Step 2: Make sure you have a XAML template properly named to correspond with the part

We have three parts we’re getting here, so this is a stripped down template that just has the three PARTs named appropriately. If the names are not the same as the strings above, it will not work.

<StyleTargetType="local:MyControl">
    <
SetterProperty="Template">
        <
Setter.Value>
            <
ControlTemplate TargetType="local:MyControl">
                <
Grid x:Name="PART_RootElement">
                    <
Grid.Resources>
                        <
Storyboard x:Name="PART_MyStoryboard">
                          
<!– Whatever animations you want here –>
                      
</Storyboard>
                    </
Grid.Resources>
                    <
Button x:Name="PART_MyButton" />                       
                </
Grid>
            </
ControlTemplate>
        </
Setter.Value>
    </
Setter>
</
Style>

Step 3: Assign the XAML PART to the code PART in the OnApplyTemplate method

Now we just have to write a custom OnApplyTemplate method that will grab the XAML elements and assign them to objejcts within the control code. There are two key methods you’ll use. The first is GetTemplateChild, which will pull out any UI element in the XAML that is named and not in the resources.

If you want to get something in the resources, you need to refer to the UI element that holds those resources. This is why we needed the root element as a PART. So, enough of my blabbing… here’s the code:

public override void OnApplyTemplate()
{
    base.OnApplyTemplate();

    _rootElement = GetTemplateChild(MyControl.RootElementString) as FrameworkElement;
    //Make sure we actually got the template applied.
   
if (_rootElement != null)
    {
        _targetStoryboard = _rootElement.Resources[MyControl.StoryboardString] as Storyboard;
        _targetButton = GetTemplateChild(MyControl.ButtonString) as Button;

        _targetButton.Click +=new RoutedEventHandler(_targetButton_Click);       

    }
}

Now we have all the PARTs assigned so we can do something like adding an event handler to the Button so that, when it is clicked, it runs the storyboard.

void  _targetButton_Click(objectsender, RoutedEventArgs e)
{
     _targetStoryboard.Begin();
}

And that’s how you add a PART… both in the regular XAML template and in the resources of the template.