Creating control templates

In today's world, professionals want to use a wide array of controls such as Button, TextBox, Slider, and so on. In many cases, you don't want to reinvent the wheel but just use the basic control in a way that fits your design. How many times did you want to have a round button? Or a control that does the exact same action as a slider but looks completely different? To answer these kinds of issues the concept of templates was introduced. Templating, as the name implies, allows you to completely change the way a control looks without sacrificing its behavior. To template a control, you first need a control. Let's create a new Silverlight application project, name it Chapter3-Templates and leave all the default options. Once the project is ready, add a button to the page using the following code:

<Button Width="100" Height="100" Content="Round" Click="Button_Click"> </Button>

Switch over to the code behind file (MainPage.xaml.cs), and add the following event handler:

private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("I'm clicked!");
}

Here, there is nothing that we haven't seen before. We've added a button, whose content is"Round", and once you click on it, a message box pops out saying I'm clicked!

To make things interesting (the button is called Round after all), we are going to template the button to look like a round button. One way to template a control is to use its Template attached property. Change your button code, so it will look like the following code snippet:

<Button Width="100" Height="100" Content="Round" Click="Button_Click">
<Button.Template>
<ControlTemplate>
<Ellipse Height="100" Width="100" Stroke="Blue" StrokeThickness="1" Fill="Pink"/>
</ControlTemplate>
</Button.Template>
</Button>

By using the Template attached property of Button, we can set the ControlTemplate property, which tells the Silverlight engine how to render the UI of the control. In our example, we've created a simple Ellipse shape, which is perfectly rounded as its width and height are set to the same value. If you run your application now, you would see that the button has changed the way it looks to a pink circle with a blue stroke but retained its buttonly behavior. If you click on it, the following message box will pop:

Creating control templates

TemplateBinding

As nice as the template we've just created is, it has a big flaw. Its height and width values are hardcoded. With hardcoded width and height, the button loses its ability to resize according to its properties, and we are basically left with a fixed-size button. To solve this issue, we have the TemplateBinding mechanism. TemplateBinding is part of the data binding family, and it can only be used within ControlTemplate. The source of TemplateBinding is the control to which the ControlTemplate it resides in refers to.

Let's change our fixed-size Width and Height properties to use the TemplateBinding mechanism. Change your Ellipse element in your ControlTemplate as follows:

<Ellipse Height="{TemplateBinding Height}" Width="{TemplateBinding Width}" Stroke="Blue" StrokeThickness="1" Fill="Pink"/>

By replacing the fixed size values and using the TemplateBinding mechanism, we are telling Silverlight that whatever width and height we set on the parent element (Button in our case), the same values should also be used in our template. Change the values of the Width and Height properties in the Button element, and then build and run your application. You'll notice that whatever values you put in these properties affect the size of your button template. TemplateBinding isn't limited to the Width and Height properties. In your template, you can set TemplateBinding to just about any other property such as Background, Foreground, FontSize, and so on.

Showing the content

You may have noticed that something is still missing in our button template—the content of the button! When creating a template for a control, we have to tell Silverlight where we want to place our content. In order to accomplish this task, Silverlight provides us with two specially designed elements—ContentPresenter and ItemPresenter. Each of these elements has a very distinct job when it comes to show content, and for that reason, we will discuss them right now.

The ContentPresenter element

The ContentPresenter element is nothing more than a placeholder for the content. Its job is to take the content of the element—be it some text, an image, another control and so on—and place it in your template. To best demonstrate this control, change your ControlTemplate element as follows:

<Grid>
<Ellipse Height="{TemplateBinding Height}" Width="{TemplateBinding Width}" Stroke="Blue" StrokeThickness="1" Fill="Pink"/>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>

By placing the Ellipse element inside a Grid and adding the ContentPresenter element, we've added the content back to the button. The content itself comes from the Content property of the parent control and presents wherever we place ContentPresenter in our template. In our example, the content will be shown in the center of the Ellipse element, because the ContentPresenter element's HorizontalAlignment and VerticalAlignment properties are set to center.

Play around with the Content property of the button, and then build and run your application. You'll notice the content—no matter if it's text or anything else—is always presented in the middle of the button:

The ContentPresenter element

The ItemPresenter element

While the ContentPresenter element is perfect for showing content, if you are templating a control based on ItemsControl, such as ListBox, you're better off using the ItemPresenter element. The ItemPresenter element's job is to place the items in your template but not templating the items themselves. We will deal with item templating later in this chapter. To demonstrate the ItemPresenter element, replace your Button control with the following ListBox control:

<ListBox x:Name="myTemplatedListBox" Height="300" Width="300">
<ListBox.Template>
<ControlTemplate>
<Border CornerRadius="20" BorderThickness="15" BorderBrush="Cyan" Padding="5">
<ItemsPresenter></ItemsPresenter>
</Border>
</ControlTemplate>
</ListBox.Template>
<ListBoxItem Content="Item 1"/>
<ListBoxItem Content="Item 2"/>
<ListBoxItem Content="Item 3"/>
</ListBox>

Build and run your application, and you'll be presented with the following result:

The ItemPresenter element

By templating the ListBox control, we've added a nice rounded cyan-flavored border around the control itself. The ItemPresenter element was used to place the ListBox control's items inside that border. Play around with the template, and add your own controls inside of it. Templating is all about your creativity after all.

Attaching the style

Up until now, we've only created templates on the element level. Just like styling however, we can create templates on larger scales such as the page and global levels.

Consider the following scenario:

You are in charge of templating a form in Silverlight that contains three comboboxes and two buttons. If you try to template these controls like we did so far in this chapter, you'll end up using duplicate, messy, and error-prone code. Each of the controls will have its own template, which is a duplication of the other control template. To solve this mess, we will use either the page-level or the global-level templating. Let's change the ListBox template we have just created from element level to global level. The process of such a change is quite simple. First, delete the ListBox template, which we've previously created for the ListBox element, from your MainPage.xaml file. Once done, open the App.xaml file, and create a new implicit style using the following line of code:

<Style TargetType="ListBox"></Style>

Template is a property just like any of the other properties we've seen while creating a style. To set a control's template in a style, examine the following code snippet:

<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border CornerRadius="20" BorderThickness="15" BorderBrush="Cyan" Padding="5">
<ItemsPresenter></ItemsPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>

We are defining a Setter element with the property of Template and by using attached properties we are setting the Value of that property to the template we've already created in the previous exercise. As this is an implicit style, ListBox on the mainpage.xaml page will be affected by it immediately. Build and run your application, and you should see that the ListBox control still retains its cyan border.

Note

If we were to create an explicit-style template, all we would have to change in our code is the binding name of the style that holds the template to the Style property of the control we wish to template.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.200.3