In an earlier post, I wrote about how to develop a Silverlight custom content control. Since then I’ve received inquiries as to how to add events to it. More specifically, how can we add interactivity to the control and have the control raise events which can be handled by the consumer of our control.
Step 1: Add Template UI Elements to Receive User Interaction
In the previous post, I described how to create a generic.xaml file to house our templated control UI (style). In this example, I am going to create a close HyperlinkButton and raise a close event. Here’s our style which is defined in the generic.xaml file. Take not of our new hlbClose HyperlinkButton (line 34).
1: <ResourceDictionary
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:local="clr-namespace:ContentControlExample.Controls">
5:
6: <!-- CustomContentControl -->
7: <Style TargetType="local:CustomContentControl">
8: <Setter Property="Background" Value="Transparent" />
9: <Setter Property="Foreground" Value="Black" />
10: <Setter Property="BorderBrush" Value="Transparent" />
11: <Setter Property="BorderThickness" Value="0" />
12: <Setter Property="HorizontalAlignment" Value="Stretch" />
13: <Setter Property="VerticalAlignment" Value="Stretch" />
14: <Setter Property="HorizontalContentAlignment" Value="Left" />
15: <Setter Property="VerticalContentAlignment" Value="Top" />
16: <Setter Property="Template">
17: <Setter.Value>
18: <ControlTemplate TargetType="local:CustomContentControl">
19: <Border Background="White" BorderBrush="#87AFDA" BorderThickness="1">
20: <Grid>
21: <Grid.RowDefinitions>
22: <RowDefinition Height="Auto" />
23: <RowDefinition Height="*" />
24: </Grid.RowDefinitions>
25:
26: <Border Grid.Column="0" Grid.Row="0" Background="#D4E6FC" BorderThickness="0,0,0,1" BorderBrush="#87AFDA">
27: <Grid>
28: <Grid.ColumnDefinitions>
29: <ColumnDefinition />
30: <ColumnDefinition Width="20" />
31: </Grid.ColumnDefinitions>
32:
33: <ContentControl Grid.Column="0" Content="{TemplateBinding Header}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Foreground="#224499" FontWeight="Bold" FontFamily="Arial" FontSize="12" Margin="3,3,3,3" />
34: <HyperlinkButton x:Name="hlbClose" Grid.Column="1" Content="[X]" />
35: </Grid>
36: </Border>
37: <ContentControl Grid.Column="0" Grid.Row="1" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" Cursor="{TemplateBinding Cursor}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" FontFamily="Arial" FontSize="{TemplateBinding FontSize}" FontStretch="{TemplateBinding FontStretch}" Foreground="{TemplateBinding Foreground}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
38: </Grid>
39: </Border>
40: </ControlTemplate>
41: </Setter.Value>
42: </Setter>
43: </Style>
44: </ResourceDictionary>
Step 2: Get a Handle to Template UI Elements
Once we have our control UI looking the way we want it, the next step is to get a handle to our HyperlinkButton and add a handler for its click event. When the user clicks the HyperlinkButton, we want to raise our control’s Close event. The trick is to override the OnApplyTemplate of our control and get our handle to the HyperlinkButton using the GetTemplateChild method. The GetTemplateChild method accepts the id/name of the control we are looking for. It traverses the visual tree and returns a DependencyObject if found. Below I show how we can do this:
1: Public Class CustomContentControl
2: Inherits ContentControl
3:
4: Private _hlbClose As HyperlinkButton
5:
6: Public Shared ReadOnly HeaderProperty As DependencyProperty = DependencyProperty.Register("Header", GetType(UIElement), GetType(CustomContentControl), Nothing)
7: Public Event Close(ByVal sender As CustomContentControl)
8:
9: Public Property Header() As UIElement
10: Get
11: Return DirectCast(Me.GetValue(CustomContentControl.HeaderProperty), UIElement)
12: End Get
13: Set(ByVal value As UIElement)
14: Me.SetValue(CustomContentControl.HeaderProperty, value)
15: End Set
16: End Property
17:
18: Public Sub New()
19: MyBase.New()
20: Me.DefaultStyleKey = GetType(CustomContentControl)
21: End Sub
22:
23: Public Overrides Sub OnApplyTemplate()
24: MyBase.OnApplyTemplate()
25: _hlbClose = DirectCast(GetTemplateChild("hlbClose"), HyperlinkButton)
26: AddHandler _hlbClose.Click, AddressOf hlbClose_Click
27: End Sub
28:
29: Private Sub hlbClose_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
30: RaiseEvent Close(Me)
31: End Sub
32: End Class
Step 3: Raise Control Events
Now that we have acquired a handle to our HyperlinkButton and also have added a handler for its click event, all we have to do now is raise our control’s Close event when the HyperlinkButton is clicked. The control consumers can handle the close event if they wish.
1: Private Sub hlbClose_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
2: RaiseEvent Close(Me)
3: End Sub
ContentControlExample_Soln.zip (627.32 kb)