Saturday, December 18, 2010

Silverlight Control template for content controls

One of the strongest things about silverlight is that it gives you the complete control over your application visual appearance.

Unlike win-forms controls or asp.net controls, the look of the control and it's behavior are two different things.

For example, a button is Clickable but it doesn't have to look like a button, it can be a bunch of circles or whatever you like.

So how you change the control appearance?

It depends on what you want to do… let's say we want to create a round Button.

We can try to create a Border element around it, like this:

 <Border BorderThickness="5" CornerRadius="15" BorderBrush="Black">
            <Button Content="Click me!" />
 </Border>

Now we have a round border around our button, but it's still a regular button:

image

So we have to get into the actual control and change it's complete appearance , and how? by changing the control's template.

The control template defines the visual-tree of the control.

In order to create our round button I created a style that defines the visual tree of the button as an ellipse.

 <Style TargetType="Button">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
                        <Ellipse  Opacity="0.8">
                            <Ellipse.Fill>
                                <SolidColorBrush x:Name="Brush" Color="LightGreen"/>
                            </Ellipse.Fill>
                        </Ellipse>
                        <ContentPresenter Margin="{TemplateBinding Padding}" VerticalAlignment="Center"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
</Style>

So what did I do here?

I've changes the button to be a grid that has an ellipse and something to holds it's content (Content presenter) on top of the ellipse.

When someone that use's this template define a content for the button(it can be some text,another control etc..), the content will be presented on the ellipse.

The button with text content:

image

The button with 2 ellipses as a content:

image

Note: this is still a button! when you click on it, it fires the "Click" event!

Another important thing to mention is that when you create your own template for the control, you actually run-over the default template, and by doing so, loses some things like the management of visual states of the control, which means you need to create them yourself (like I did in this post).

The code with the visual states(simple mouse-over) will look like this:

<Style TargetType="Button">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="Brush"    
                                                        Storyboard.TargetProperty="Color" Duration="0:0:0"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="Brush" 
                                                                    Storyboard.TargetProperty="Color"
                                                                    To="Pink"  Duration="0:0:0"/>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Ellipse  Opacity="0.8">
                            <Ellipse.Fill>
                                <SolidColorBrush x:Name="Brush" Color="LightGreen"/>
                            </Ellipse.Fill>
                        </Ellipse>
                        <ContentPresenter Margin="{TemplateBinding Padding}" VerticalAlignment="Center"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
</Style>

Last thing, this post is for content controls, and why is that? because we use Content Presenter as a placeholder for the content.

But what if it's a TextBox that does not have content? well,this is for the next post… סמיילי

No comments:

Post a Comment