Wednesday, August 4, 2010

Customizing Silverlight Controls

Customizing Silverlight Controls
The best thing about Silverlight controls is that their appearance and behavior can be changed dramatically without affecting the functionality of the control.
For example a Button may display a simple text or it can display a grid on itself. The shape of a button can be left as default or it can be changed to a circle.
Introduction:
This document provides basic information that is very helpful in learning how the visual appearance of a Silverlight control can be changed. It is determines various ways of changing appearance and provide code samples.
Customizing Controls
Customization can be done by setting simple values in the properties or by storing a complex structures for example

<button name="SimpleBackground" type="submit" content="Hello" background="Yellow"></button>

<button name="ComplexBackground" type="submit" content="Hello">
<button.background>
<lineargradientbrush endpoint="1,1" startpoint="0,0">
<gradientstop color="Green" offset="0.2"></gradientstop>
<gradientstop color="Yellow" offset="1"></gradientstop>
</lineargradientbrush>
</button.background>

</button>
</pre>


In the above XAML, Button named “SimpleBackground” stores a simple color in Background where as “ComplexBackground” associates a complex structure.
Similarly the content of control can be set to a simple string or it can be set to a complex group of other controls. The example below instructs Silverlight to make a button that has a checkbox placed on it.
<button name="ComplexBackground" type="submit" row="0" column="1">
<button.background>
<lineargradientbrush endpoint="1,1" startpoint="0,0">
<gradientstop color="Green" offset="0.2"></gradientstop>
<gradientstop color="Yellow" offset="1"></gradientstop>
</lineargradientbrush>
</button.background>
<button.content>
<checkbox content="Click Me">
</button.content>
</button>

Following is the complete example which displays two buttons one of which is simple one displaying plain text and single color background, whereas the other has multi-color background and consists of a checbox .
<grid name="LayoutRoot" background="White" showgridlines="True">
<grid.columndefinitions>
<columndefinition width="*"></columndefinition>
<columndefinition width="4*"></columndefinition>
</grid.columndefinitions>
<grid.rowdefinitions>
<rowdefinition height="Auto"></rowdefinition>
</grid.rowdefinitions>

<button name="SimpleBackground" type="submit" content="Hello" background="Yellow" row="0" column="0"></button>


<button name="ComplexBackground" type="submit" row="0" column="1">
<button.background>
<lineargradientbrush endpoint="1,1" startpoint="0,0">
<gradientstop color="Green" offset="0.2"></gradientstop>
<gradientstop color="Yellow" offset="1"></gradientstop>
</lineargradientbrush>
</button.background>
<button.content>
<checkbox content="yo"></checkbox>
</button.content>
</button>


</grid>

Other Ways to Change Visual Appearance of Controls
The above code demonstrates how the visual appearance of a control can be changed using properties however in some cases you may want a single style to be applied to a number of controls. This can be done in two ways
• Using Styles
• Using ControlTemplate
Using Styles:
Styles are a collection of property values that can be applied to controls of particular type. The style can be stored in a separate file for global usage. The “TargetType” property of a style specifies the controls to which the style can be applied to. It is also possible to specify a key for the style, in which case the style will only be applied to controls which refer to that key.
Following code demonstrates how a style can be created
<pre>
<usercontrol.resources>
<style targettype="Button">
<setter property="Background">
<setter.value>
<lineargradientbrush startpoint="0,0" endpoint="1,1">
<gradientstop offset="0.2" color="Green"></gradientstop>
<gradientstop offset="1" color="Yellow"></gradientstop>
</lineargradientbrush>

</Setter.Value>

</setter>
<setter property="FontFamily" value="Arial Black"></setter>
<setter property="MaxWidth" value="100"></setter>
<setter property="MaxHeight" value="50"></setter>


</style>

</usercontrol.resources>
<pre>
Once the above style is created, all controls belonging to the type mentioned in the TargetType property will have the same property values as indicated in the style. For example, the following code creates two buttons. Although not mentioned explicitly but these buttons will have the style created above as both of them belong to the type button.


<button type="submit" content="Button1" row="1" column="1">
<button type="submit" content="Button2" row="1" column="2">

Using Control Template

Control Templates are used in case where we want to completely customize the look and feel as well as behavior of controls. E.g. of complete customization includes replacing or removing parts of a control or adding new parts. For simply setting the properties to certain values, Style is simplest and best choice.

ControlTemplate combine FrameworkElement objects to build a single control. A controlTemplate must have a single FrameworkElement at its root.

The Template property of a control is used to specify the ControlTemplate for that control. Template property can be set in the following three ways
• Set the Template property to an Inline template
<pre>
</pre><button type="submit" content="Button1">
<button.template>
<controltemplate targettype="Button">

<!--Define the ControlTemplate here.-->

</controltemplate>
</button.template>
</button>
<pre></pre>
• Set the Template property to reference ControlTemplate defined as a resource
<pre>
<grid>
<grid.resources>
<controltemplate targettype="Button" key="newTemplate">

<!--Define the ControlTemplate here.-->

</controltemplate>
</grid.resources>

<button type="submit" template="{StaticResource newTemplate}" content="Button1">
</grid>
<pre></pre>
• Define Template in a Style and link control to that style
<pre>
<stackpanel>
<stackpanel.resources>
<style targettype="Button" key="newTemplate">
<setter property="Template">
<setter.value>
<controltemplate targettype="Button">

<!--Define the ControlTemplate here.-->

</controltemplate>
</Setter.Value>
</setter>
</style>
</stackpanel.resources>
</pre><button type="submit" content="Button1">
</stackpanel>
<pre></pre>
Following is an example that sets the template for a control by combining a number of framework elements
<pre>
<usercontrol.resources>
<style targettype="Button">
<setter property="Template">
<setter.value>
<controltemplate>
<grid>
<rectangle width="200" height="100" fill="Blue" stroke="Black" strokethickness="7">
<ellipse width="100" height="100" fill="Transparent" stroke="Yellow" strokethickness="5"></ellipse>
<textblock text="Click Me" horizontalalignment="Center" verticalalignment="Center" foreground="White"></textblock>
</grid>
</controltemplate>
</Setter.Value>
</setter>
</style>
</usercontrol.resources>
</pre>
Binding Template to Control Properties using TemplateBinding

One more requirement can arise, that the user of control may want the Template to get some values from the control. For example, we want the color of Rectangle within a template to be that which has been assigned to the background property of Button to which the template is being applied.

The TemplateBinding Markup Extension serves this purpose. It enables the template to change itself based upon the public properties of control. The following code indicates that the value of Fill property will be set by the value of Background property of control
<pre>
<rectangle width="200" height="100" strokethickness="7" stroke="Black" fill="{TemplateBinding Background}">
</pre>
It must also be noted that the Control class defines several properties that can be used by ControlTemplate to have an effect on the control when they are set.

Using ContentPresenter:

One more flexibility is that we can include ContentPresenter in the template rather than controls like TextBlock or Button. This enables the user of control to set a group of controls in the content rather than just text.

Following is the complete example demonstrates the usage of ContentPresenter
<pre>
<usercontrol.resources>
<style targettype="Button">
<setter property="Template">
<setter.value>
<controltemplate>
<grid>
<rectangle width="200" height="100" fill="{TemplateBinding Background}" stroke="Black" strokethickness="7">
<ellipse width="100" height="100" fill="Transparent" stroke="Yellow" strokethickness="5"></ellipse>
<contentpresenter content="{TemplateBinding Content}" horizontalalignment="Center" verticalalignment="Center"></contentpresenter>

</grid>
</controltemplate>
</Setter.Value>
</setter>
</style>
</usercontrol.resources>
<grid name="LayoutRoot" background="White">
</pre><button type="submit" content="Hello" background="Aqua">

</button>

</grid>

</pre>
Customizing Controls by Understanding the Control Contract

Controls that uses ControlTemplate to specify visual structure use Parts Control Model. Many controls that are offered by Microsoft and third-parties follow this model. As per this model, it can be said that a control is made up of “Parts”. The information about these parts of a control is communicated through the control contract. Understanding control contract is very helpful in customizing the appearance of control based on a template

Contract has three elements
• Visual Elements
o These are used by the logic inside a control. In other words the code of control has references to certain FrameworkElements. Therefore the template must have objects for these references. The control uses the TemplatePartAttribute to convey the type of element that is expected, and what the name of the element should be.
• States
o The states of a control are also a part of the control contract. The states of a control are specified by the TemplateVisualStateAttribute
• Public properties
o Public properties are also considered as a part of contract. The properties can also be set without creating any ControlTemplate

Conclusion:

Appearance of Silverlight controls can be changed by
• Directly setting properties
• Creating Styles
• Creating Templates

Understanding control contract is very helpful in creating templates for a control. The class of control communicates the control contract by using TemplatePartAttribute and TemplateVisualStateAttribute