Matt Casto's .NET Journal RSS 2.0
 Saturday, April 12, 2008

I haven't been posting much lately because I've been very busy preparing for my session at the Central Ohio Day of .NET.  I'm creating a presentation about Silverlight 2.0 Beta 1, but with a twist - the presentation is actually a Silverlight application!

Templates

For the last day or so I've been working on getting my application's main control to use templates to define the interface.  This gives me the option to create multiple "skins" for the application.

To accomplish this, I've been referencing two very excellent tutorials by Jesse Liberty and Shawn Burke.  But, as usual for me, I ran into a problem that sucked up a ton of time.

The Problem

I was trying to set up my template to include buttons for navigation between slides.  I started by building a simple XAML interface for the buttons, like so.

<StackPanel Orientation="Horizontal">
    <Button Height="75" Width="75" Margin="0,0,8,0">
        <TextBlock Text="First" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Button>
    <Button Height="75" Width="75" Margin="0,0,8,0">
        <TextBlock Text="Prev" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Button>
    <Button Height="75" Width="75" Margin="0,0,8,0">
        <TextBlock Text="Next" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Button>
    <Button Height="75" Width="75">
        <TextBlock Text="Last" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Button>
</StackPanel>

 

And that looks good enough for this example.

 

Then I took that same XAML and put it into a template stored in the application resources (in App.xaml).

<Application.Resources>
  <Style x:Key="TestTemplate" TargetType="pl:Presentation">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="pl:Presentation">
          <StackPanel Orientation="Horizontal">
            <Button Height="75" Width="75" Margin="0,0,8,0">
              <TextBlock Text="First" HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Button>
            <Button Height="75" Width="75" Margin="0,0,8,0">
              <TextBlock Text="Prev" HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Button>
            <Button Height="75" Width="75" Margin="0,0,8,0">
              <TextBlock Text="Next" HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Button>
            <Button Height="75" Width="75">
              <TextBlock Text="Last" HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Button>
          </StackPanel>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</Application.Resources>

And modified my Page.xaml to have my Presentation UserControl class (modeled after Shawn Burke's tutorial) with the template applied as a style.

<local:Presentation x:Name="PresentationControl" Style="{StaticResource TestTemplate}" />

But running this treated me to a browser window that's stuck loading.  My break point in OnApplyTemplate in my Presentation class never got hit.  Pausing Visual Studio didn't tell me anything, so I knew it wasn't stuck in a loop.  This had me stuck for several hours.

The Solution

What I eventually found was that certain things that are perfectly acceptable XAML in a user control won't work in a template.  Furthermore, if Silverlight encounters these elements in the template it just hangs.

The problem XAML was the buttons.  Instead of including your actual buttons in your template, you should instead create a separate template for the buttons, and reference that as your button style.

<Style x:Key="TestButton" TargetType="Button">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="Button">
        <Button Width="75" Height="75">
          <Button.Content>
            <ContentPresenter Content="{TemplateBinding Content}" 
                              HorizontalAlignment="Center" 
                              VerticalAlignment="Center" />
          </Button.Content>
        </Button>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Then modify the previous template to use the new button template.

<Application.Resources>
  <Style x:Key="TestTemplate" TargetType="pl:Presentation">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="pl:Presentation">
          <StackPanel Orientation="Horizontal">
            <Button x:Name="FirstButtonElement" Content="First" 
                    Style="{StaticResource TestButton}" Margin="0,0,8,0" />
            <Button x:Name="PreviousButtonElement" Content="Prev" 
                    Style="{StaticResource TestButton}" Margin="0,0,8,0" />
            <Button x:Name="NextButtonElement" Content="Next" 
                    Style="{StaticResource TestButton}" Margin="0,0,8,0" />
            <Button x:Name="LastButtonElement" Content="Last" 
                    Style="{StaticResource TestButton}" />
          </StackPanel>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</Application.Resources>

Finally, this works.  It looks the same, but now I can take the template and make it look much nicer if I want.

Hopefully this tip will help others working on templating in Silverlight avoid the pitfalls I ran into.

Saturday, April 12, 2008 5:45:08 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1] -
silverlight
Central Ohio Day of .NET

About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2008
Matt Casto
Sign In
All Content © 2008, Matt Casto
Theme based on DasBlog theme 'Business' created by Christoph De Baene (delarou)