Silverlight Custom Content Control with Events

July 6, 2009 08:40 by wjchristenson2

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).

<ResourceDictionary 
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:local="clr-namespace:ContentControlExample.Controls">
     
	<!-- CustomContentControl -->
	<Style TargetType="local:CustomContentControl">
		<Setter Property="Background" Value="Transparent" />
		<Setter Property="Foreground" Value="Black" />
		<Setter Property="BorderBrush" Value="Transparent" />
		<Setter Property="BorderThickness" Value="0" />
		<Setter Property="HorizontalAlignment" Value="Stretch" />
		<Setter Property="VerticalAlignment" Value="Stretch" />
		<Setter Property="HorizontalContentAlignment" Value="Left" />
		<Setter Property="VerticalContentAlignment" Value="Top" />
		<Setter Property="Template">
		<Setter.Value>
			<ControlTemplate TargetType="local:CustomContentControl">
				<Border Background="White" BorderBrush="#87AFDA" BorderThickness="1">
					<Grid>
						<Grid.RowDefinitions>
							<RowDefinition Height="Auto" />
							<RowDefinition Height="*" />
						</Grid.RowDefinitions>
                                
						<Border Grid.Column="0" Grid.Row="0" Background="#D4E6FC" BorderThickness="0,0,0,1" BorderBrush="#87AFDA">
							<Grid>
								<Grid.ColumnDefinitions>
									<ColumnDefinition />
									<ColumnDefinition Width="20" />
								</Grid.ColumnDefinitions>
                                    
								<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" />
								<HyperlinkButton x:Name="hlbClose" Grid.Column="1" Content="[X]" />
							</Grid>
						</Border>
						<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}" />
					</Grid>
				</Border>
			</ControlTemplate>
		</Setter.Value>
		</Setter>
	</Style>
</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:

Public Class CustomContentControl
    Inherits ContentControl

    Private _hlbClose As HyperlinkButton

    Public Shared ReadOnly HeaderProperty As DependencyProperty = DependencyProperty.Register("Header", GetType(UIElement), GetType(CustomContentControl), Nothing)
    Public Event Close(ByVal sender As CustomContentControl)

    Public Property Header() As UIElement
        Get
            Return DirectCast(Me.GetValue(CustomContentControl.HeaderProperty), UIElement)
        End Get
        Set(ByVal value As UIElement)
            Me.SetValue(CustomContentControl.HeaderProperty, value)
        End Set
    End Property

    Public Sub New()
        MyBase.New()
        Me.DefaultStyleKey = GetType(CustomContentControl)
    End Sub

    Public Overrides Sub OnApplyTemplate()
        MyBase.OnApplyTemplate()
        _hlbClose = DirectCast(GetTemplateChild("hlbClose"), HyperlinkButton)
        AddHandler _hlbClose.Click, AddressOf hlbClose_Click
    End Sub

    Private Sub hlbClose_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        RaiseEvent Close(Me)
    End Sub
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.

    Private Sub hlbClose_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        RaiseEvent Close(Me)
    End Sub

ContentControlExample_Soln.zip (627.32 kb)

Bookmark and Share