Expander Control

Expander Control is a Collapsable panel, which when collapsed shows only header and button, when expanded the content is displayed.

www.cespage.com/silverlight/sl4tut24.html

Step 1

Start Microsoft Visual Web Developer 2010 Express, then Select File then New Project... Select "Visual Basic" then "Silverlight Application" from Templates, select a Location if you wish, then enter a name for the Project and then click OK, see below:

New Project

Step 2

New Silverlight Application window should appear, uncheck the box "Host the Silverlight Application in a new Web site" and then select the required Silverlight Version, see below:

New Silverlight Application

Step 3

A Blank Page named MainPage.xaml should then appear, see below:

MainPage.xaml

Step 4

Select from the Main Menu: "File" then "Add", then "New Project..." The "New Project" window should appear, select "Silverlight Class Library" with the Name "Expander" without the quotes, see below:

Add Silverlight Class Library Project

Step 5

In the "Choose the version of Silverlight you want to target from the list of installed Silverlight SDK's" choose the same version of Silverlight for example Silverlight 4 and click OK.
Then in the Solution Explorer for "Expander", click on the "Class1.vb" entry, then goto Properties and change the File Name to "Expander.vb" (without the quotes), see below:

Expander Class Properties

Step 6

In the "You are renaming a file. Would you also like to perform a rename in this project of all references to the code element 'Class1'?" choose Yes.
Right Click on the Entry for the "Expander" Project (not the Expander.vb) in Solution Explorer and choose "Add" then "New Folder", and give it the Name "Themes" (again without quotes), see below:

Expander Project Themes Folder

Step 7

Right Click on the Entry for the "Themes" Folder for the Expander Project, and choose "Add", then "New Item...", select "Silverlight Resource Dictionary" with the Name "Generic.xaml", without quotes, see below:

Generic.xaml Resource Dictionary

Step 8

In the XAML Pane for the Generic.xaml, in the "ResourceDictionary" tag type the following XAML namespace:

xmlns:local="clr-namespace:Expander"

See below:

Resource Dictionary Namespaces

Step 9

While still the XAML Pane for the Generic.xaml, above the "</ResourceDictionary>" tag and below the top "<ResourceDictionary>" tag, type the following XAML:


<Style TargetType="local:Expander">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="local:Expander">
        <Grid>
          <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="ViewStates">
              <VisualStateGroup.Transitions>
                <VisualTransition GeneratedDuration="0:0:0.5"/>
              </VisualStateGroup.Transitions>
              <VisualState x:Name="Expanded">
                <Storyboard>
                  <DoubleAnimation Storyboard.TargetName="ContentScaleTransform"
                      Storyboard.TargetProperty="ScaleY" To="1" Duration="0"/>
                  <DoubleAnimation Storyboard.TargetName="RotateButtonTransform"
                      Storyboard.TargetProperty="Angle" To="180" Duration="0"/>
                </Storyboard>
              </VisualState>
            <VisualState x:Name="Collapsed">
              <Storyboard>
                <DoubleAnimation Storyboard.TargetName="ContentScaleTransform"
                    Storyboard.TargetProperty="ScaleY" To="0" Duration="0"/>
                <DoubleAnimation Storyboard.TargetName="RotateButtonTransform"
                    Storyboard.TargetProperty="Angle" To="0" Duration="0"/>
              </Storyboard>
            </VisualState>
          </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
          <Border BorderBrush="{TemplateBinding BorderBrush}"
              BorderThickness="{TemplateBinding BorderThickness}"
              CornerRadius="{TemplateBinding CornerRadius}"
              Background="{TemplateBinding Background}">
            <Grid>
              <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
              </Grid.RowDefinitions>
              <Grid Margin="3">
                <Grid.ColumnDefinitions>
                  <ColumnDefinition Width="Auto"/>
                  <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <ContentPresenter Margin="3" Content="{TemplateBinding HeaderContent}"/>
                <ToggleButton Grid.Column="1" RenderTransformOrigin="0.5,0.5" Margin="3" x:Name="ExpandCollapseButton">
                  <ToggleButton.Template>
                    <ControlTemplate>
                      <Grid>
                        <Ellipse Width="20" Height="20" Stroke="#FFA9A9A9" Fill="AliceBlue"/>
                        <Path RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center" VerticalAlignment="Center" 
                            Data="M1,1.5L4.5,5 8,1.5" Stroke="#FF666666" StrokeThickness="2"/>
                      </Grid>
                    </ControlTemplate>
                  </ToggleButton.Template>
                  <ToggleButton.RenderTransform>
                    <RotateTransform x:Name="RotateButtonTransform"/>
                  </ToggleButton.RenderTransform>
                </ToggleButton>
              </Grid>
              <ContentPresenter Grid.Row="1" Margin="5" Content="{TemplateBinding Content}" x:Name="Content">
                <ContentPresenter.RenderTransform>
                  <ScaleTransform x:Name="ContentScaleTransform"/>
                </ContentPresenter.RenderTransform>
              </ContentPresenter>
            </Grid>
          </Border>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

See below:

Expander Resource Dictionary

Step 10

Double Click on the Entry for the "Expander.vb" Class in Solution Explorer in the "Expander" project.
In the Code View for Expander above the "Public Class Expander" line type the following:

Imports System.Windows.Controls.Primitives
<TemplateVisualState(Name:="Collapsed", GroupName:="ViewStates"),
TemplateVisualState(Name:="Expanded", GroupName:="ViewStates"),
TemplatePart(Name:="Content", Type:=GetType(FrameworkElement)),
TemplatePart(Name:="ExpandCollapseButton", Type:=GetType(ToggleButton))>

See Below:

Expander.vb Imports and Template

Step 11

While still in the Code View for Expander.vb, below the "Public Class Expander" line type the following:

Inherits ContentControl

Private _useTransitions As Boolean = True
Private _collapsedState As VisualState
Private _toggleExpander As ToggleButton
Private _contentElement As FrameworkElement

See Below:

Expander.vb Declarations

Step 12

While still in the Code View for Expander.vb, above the "End Class" for "Public Class Expander", type the following Dependency Properties:

Public Shared ReadOnly HeaderContentProperty As DependencyProperty =
DependencyProperty.Register("HeaderContent", GetType(Object),
GetType(Expander), Nothing)

Public Shared ReadOnly IsExpandedProperty As DependencyProperty =
DependencyProperty.Register("IsExpanded", GetType(Boolean),
GetType(Expander), New PropertyMetadata(True))

Public Shared ReadOnly CornerRadiusProperty As DependencyProperty =
DependencyProperty.Register("CornerRadius", GetType(CornerRadius),
GetType(Expander), Nothing)

See Below:

Expander.vb Dependancy Properties

Step 13

While still in the Code View for Expander.vb, above the "End Class" for "Public Class Expander", type the following Properties:

Public Property HeaderContent() As Object
  Get
    Return GetValue(HeaderContentProperty)
  End Get
  Set(ByVal value As Object)
    SetValue(HeaderContentProperty, value)
  End Set
End Property

Public Property IsExpanded() As Boolean
  Get
    Return CBool(GetValue(IsExpandedProperty))
  End Get
  Set(ByVal value As Boolean)
   SetValue(IsExpandedProperty, value)
  End Set
End Property

Public Property CornerRadius() As CornerRadius
  Get
    Return CType(GetValue(CornerRadiusProperty), CornerRadius)
  End Get
  Set(ByVal value As CornerRadius)
    SetValue(CornerRadiusProperty, value)
  End Set
End Property

See Below:

Expander.vb Properties

Step 14

While still in the Code View for Expander.vb, above the "End Class" for "Public Class Expander", type the following Constructor and Sub:

Public Sub New()
  DefaultStyleKey = GetType(Expander)
End Sub

Private Sub ChangeVisualState(ByVal useTransitions As Boolean)
  If IsExpanded Then
    If _contentElement IsNot Nothing Then
      _contentElement.Visibility = Visibility.Visible
    End If
    VisualStateManager.GoToState(Me, "Expanded", useTransitions)
  Else
    VisualStateManager.GoToState(Me, "Collapsed", useTransitions)
    _collapsedState = TryCast(GetTemplateChild("Collapsed"), VisualState)
    If _collapsedState Is Nothing Then
      If _contentElement IsNot Nothing Then
        _contentElement.Visibility = Visibility.Collapsed
      End If
    End If
  End If
End Sub

See Below:

Expander.vb Constructor and Sub

Step 15

While still in the Code View for Expander.vb, above the "End Class" for "Public Class Expander", type the following Event Handlers:

Private Sub Toggle_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
  IsExpanded = Not IsExpanded
  _toggleExpander.IsChecked = IsExpanded
  ChangeVisualState(_useTransitions)
End Sub

Private Sub Collapsed_Completed(ByVal sender As Object, ByVal e As EventArgs)
  _contentElement.Visibility = Visibility.Collapsed
End Sub

Public Overrides Sub OnApplyTemplate()
  MyBase.OnApplyTemplate()
  _toggleExpander = TryCast(GetTemplateChild("ExpandCollapseButton"), ToggleButton)
  If _toggleExpander IsNot Nothing Then
    AddHandler _toggleExpander.Click, AddressOf Toggle_Click
  End If
  _contentElement = TryCast(GetTemplateChild("Content"), FrameworkElement)
  If _contentElement IsNot Nothing Then
    _collapsedState = TryCast(GetTemplateChild("Collapsed"), VisualState)
    If (_collapsedState IsNot Nothing) AndAlso (_collapsedState.Storyboard IsNot Nothing) Then
      AddHandler _collapsedState.Storyboard.Completed, AddressOf Collapsed_Completed
    End If
  End If
  ChangeVisualState(False)
End Sub

See Below:

Expander.vb Event Handlers

Step 16

Select Debug then the "Build Expander" option from the menu, see below:

Build Expander

Step 17

Return to the MainPage.xaml Designer View by selecting the "MainPage.xaml" Tab, or Double Clicking on the Entry for "MainPage.xaml" in Solution Explorer for the Main Project.
Then from the All Silverlight Controls section in the Toolbox select the Canvas control:

Canvas Control

Step 18

Draw a Canvas that fill the whole Page or in the XAML Pane between the "<Grid>" and "</Grid>" lines type the following XAML:

<Canvas Height="300" Width="400" HorizontalAlignment="Left" VerticalAlignment="Top" Name="Page">
</Canvas>

See below:

MainPage with Canvas

Step 19

Then from the Expander Controls section in the Toolbox select the Expander control:

Expander Control

Step 20

Draw an Expander on the Page (Canvas) by dragging the Button from the Toolbox onto the Canvas, then in the XAML Pane inbetween the "<Canvas>" and "</Canvas>" tags change the "my:Expander" XAML to the following:


<my:Expander Canvas.Left="75" Canvas.Top="25" Height="250" Width="250" HeaderContent="Expander">
  <my:Expander.Content>
    <StackPanel>
      <Button Margin="4" Padding="4" Content="Button One"/>
      <Button Margin="4" Padding="4" Content="Button Two"/>
      <Button Margin="4" Padding="4" Content="Button Three"/>
      <Button Margin="4" Padding="4" Content="Button Four"/>
    </StackPanel>
  </my:Expander.Content>
</my:Expander>

See below:

MainPage with Canvas and Expander

Step 21

Save the Project as you have now finished the Silverlight application. Select Debug then Start Debugging or click on Start Debugging:

Start Debugging

After you do, the following will appear in a new Web Browser window:

Application Running

Step 22

Click on the Round button with the Arrow to Collapse or Expand the Expander, see below:

Expander Control

Step 23

Close the Application and Browser window by clicking on the Close Button Close on the top right of the Application Window and Web Browser to Stop the application.

This is a simple example of how to create an Expander, it could be extended to support more Properties such as a HeaderContent Background colour for example. Try adding more features and make it your own!