Introduction
Continuing to our second chapter of the series here on Silverlight Custom Control, in this chapter, we will discuss about dynamically setting the Content and other properties to our Custom Control that we implemented earlier. After reading this article, you will be able to create properties and set content dynamically to your control.
So, let's start describing them and learn something again today. These series of posts are mainly targeted for beginners but anyone can read them to refresh their learning. Don't forget to leave your comments at the end of the post. Any queries, please drop a line. I will try to help you as soon as I can. Don't forget to support me by providing your vote.
Background
I hope you read my previous posts. Those will help you to understand this one very easily. If you didn't read them or want to brush up before starting this chapter, find them here:
- How to create a Custom Control in Silverlight?
- How to design a Custom Control by editing the Part Template?
Once you are familiar with the previous context, let's start with this one. We will use the same example here which will give you more visualization on the sample code.
Working with the Template Part
Template parts are defined in the XAML inside the style. In our example, we have three parts called "PART_HeaderPanel
", "PART_HeaderText
" and "PART_Content
". Those are already declared in the style and you can find them here:
Now it's time to initialize them in the code. You can escape this step but it is recommended that you should do this before working with those parts. In this article, we don't need them directly but we are doing this step here itself. We will talk more about this in the next chapter.
We will declare and initialize the template part by setting the TemplatePart
attribute to the class. You need to do this for all the template parts. Again, this step is not mandatory but recommended. This also ensures that your user of this custom control should know what are the template parts that you used in your style. This information you will find in the meta class if you declare it here.
See the below sample code snippet to know how to declare the Template Part:
We are skipping the explanation and more code for the next chapter of the series.
Defining the Dependency Properties
As we discussed in our previous article, we will use dynamic content and brushes for our Custom Control. Here is the implementation of the same. In this section, we will create some properties to expose them to the user and set them dynamically on user request.
To do this, we must have to declare some dependency properties. Make sure that you are creating dependency properties only as they are used for Data Binding and Template Binding. If you use normal property, the code will not work and will throw an exception.
To implement the Dependency Property, open your control's class file (MyControl.cs, in our case) and inside the class, declare the same as per your requirement. To create a Dependency Property, you can use the code snippet called "propdp
". This will create the same and help you to properly enter the definition.
For now, we will create two dependency properties to hold the Header text and Content for the main area. We will name them as "Caption
" and "Content
" respectively.
#region Dependency Properties
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
"Content", typeof(FrameworkElement), typeof(MyControl), new PropertyMetadata(null));
public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register(
"Caption", typeof(string), typeof(MyControl), new PropertyMetadata(string.Empty));
#endregion
#region Properties
public FrameworkElement Content
{
get { return (FrameworkElement)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public string Caption
{
get { return (string)GetValue(CaptionProperty); }
set { SetValue(CaptionProperty, value); }
}
#endregion
The above code will help you to understand the same. There, we created one property called "Caption
" which is nothing but a string
type. Setting the value here will change the Header text of our control. The other property called "Content
" will be responsible to change the main content of our control.
Binding the Properties in the XAML
Once we created the dependency properties as per our requirement, it's time to bind them in the XAML. We have to modify our Template/Style present in our Generic.xaml page. Remember that you can't use normal Binding there, instead you have to use TemplateBinding
. Have a look into the below screenshot:
You will notice that we added TemplateBinding
to the properties respective to the parts. This will create the bonding between the control properties and dependency properties.
Setting Custom Value to the Properties
If we run the code now, voila!!! Our control doesn't have anything inside it. In our previous chapter, we had some text but nothing is here. Can you guess why this happened here? Just try to think the reason before scrolling next to read the answer.
If you check our dependency property, you will see that it has empty string
s and null
values as the default one that we binded. We didn't mention a new value from the user's side. So, you need to add the property values in your main page.
To do this, open the MainPage.xaml where we added our custom control. Try to add the Caption
property to the control. You will notice that the property is present in the dropdown intellisense too. Hence, add a caption to the property.
For example, we will add "My Custom Control" as the header text / caption. You can add other text too. Here is the code snippet for your reference:
Now run it once again and this time you will see that the string
which we entered to the caption
property, has been added as header title.
Similarly, we will add the content control. As our content property type is FrameworkElement
, hence we can't add normal string
there. We have to add some framework elements. If you want to give a provision to your user to add anything like FrameworkElement
and/or string
s, use "string
" as the type of the Dependency Property there.
In our case, we will add 2 textblocks inside a Stackpanel
as the content of our custom control. Have a look into the below screenshot. The code snippet will give you better visibility of what we are doing here.
Once done, run your application. This time, you will view the content that we added right now. It is so easy, right? Yes...
Let us customize it further and create another Dependency Property to take the background color of the header panel; name it as HeaderPanelBackground
. It will be a Brush
type, so that, you can add any brush
to it like Solid
color or Gradient
color.
Here is the full source code of our Custom
control class:
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media;
namespace CustomControlDemo
{
[TemplatePart(Name = "PART_HeaderPanel", Type = typeof(Border))]
[TemplatePart(Name = "PART_HeaderText", Type = typeof(TextBlock))]
[TemplatePart(Name = "PART_Content", Type = typeof(ContentPresenter))]
public class MyControl : Control
{
#region Dependency Properties
public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register("Content",
typeof(FrameworkElement),
typeof(MyControl),
new PropertyMetadata(null));
public static readonly DependencyProperty CaptionProperty =
DependencyProperty.Register("Caption",
typeof(string),
typeof(MyControl),
new PropertyMetadata(string.Empty));
public static readonly DependencyProperty HeaderPanelBackgroundProperty =
DependencyProperty.Register("HeaderPanelBackground",
typeof(Brush),
typeof(MyControl),
new PropertyMetadata(new SolidColorBrush(
Colors.Blue)));
#endregion
#region Public Properties
public Brush HeaderPanelBackground
{
get { return (Brush)GetValue(HeaderPanelBackgroundProperty); }
set { SetValue(HeaderPanelBackgroundProperty, value); }
}
public FrameworkElement Content
{
get { return (FrameworkElement)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public string Caption
{
get { return (string)GetValue(CaptionProperty); }
set { SetValue(CaptionProperty, value); }
}
#endregion
public MyControl()
{
DefaultStyleKey = typeof(MyControl);
}
}
}
It's time to bind the template
property to the style
. Get the complete source code of the control
template here:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControlDemo">
<Style TargetType="local:MyControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyControl">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition MinHeight="100" Height="*"/>
</Grid.RowDefinitions>
<Border x:Name="PART_HeaderPanel"
Background="{TemplateBinding HeaderPanelBackground}"
Grid.Row="0">
<TextBlock x:Name="PART_HeaderText"
Text="{TemplateBinding Caption}"
Foreground="White"
VerticalAlignment="Center"/>
</Border>
<ContentPresenter x:Name="PART_Content"
Grid.Row="1"
Content="{TemplateBinding Content}"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Similarly, add the HeaderPanelBackground
property value to the MainPage
where you added the Custom
Control. For example, we will use Green
color while demonstrating now.
Get the full code from here (just for reference):
<UserControl x:Class="CustomControlDemo.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:CustomControlDemo="clr-namespace:CustomControlDemo" mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<CustomControlDemo:MyControl
Width="200"
Height="200"
HeaderPanelBackground="Green"
Background="Yellow"
BorderBrush="Red"
BorderThickness="1"
Caption="My Custom Control">
<CustomControlDemo:MyControl.Content>
<StackPanel Orientation="Vertical">
<TextBlock Text="First line in Content"/>
<TextBlock Text="Second line in Content"/>
</StackPanel>
</CustomControlDemo:MyControl.Content>
</CustomControlDemo:MyControl>
</Grid>
</UserControl>
Run the application now, once again. Oh yeah, you will see that the header now has a Green
background. Change it to something else, it will automatically change. You can further customize it to dynamically change it by user input.
Hope this thing now cleared the implementation part and their usage. Try something more and you will get a chance to explore it more.
Setting Default Value to the Template
Sometimes, you may want to set the default value to the template directly. User can use the same color or can change it from the place where they use it. To do this, you can use the Setter
tag to insert default property value to the style. If you start typing the property name, it will automatically come in the intellisense.
Set the values
properly for the respective properties. Find the code snippet here:
If you run the application now, you will not see any change. To see the default value effect, go to the MainPage
and remove the properties that we already added to the control (as shown below).
Once you removed the properties, run the solution. You will see those default values as part of your UI now.
Is it clear now? Hope, this cleared the smoke from your eyes. Once you read the complete post and follow those steps properly, you will be able to create custom controls in Silverlight very easily.
What Next?
Nothing much. This series will help you to understand the implementation of Custom Controls. Though it is demonstrated in Silverlight, it will be the same for WPF, Windows Phone 7 too. In the next chapter, we will discuss the Control parts from code behind (i.e., inside the control
class). I will publish that part soon. That will be the last chapter of the series and it will cover more on the Custom control part.
Follow my blog for articles and news. Also find me on Twitter @kunal2383. You will get update there too. Also, I have a blog called Silverlight-Zone, where I post latest articles on Silverlight, LightSwitch, XAML, Blend, XNA and related articles by digging the internet. We update the site very frequently. You may follow us on twitter @SilverlightZone.
Thank you so much for reading my articles/tutorials. I appreciate your feedback and/or suggestions. Happy coding!
I appreciate your vote and support.CodeProject