Skip to main content

Silverlight Master Page

Since I'm old school and so are most of my users, I wanted to create a simple Silverlight app that had a title bar across the top, nav menu on the left side and a content area on the right. You can modify this for mutiple zones and do some pretty slick stuff. Note: This is Silverlight 2 Beta 2 and VS 2008.

image

The key is to create a Canvas that gets changed when you want to make changes. Here's the code for the above -- notice the Canvas named ContentHolder.

<UserControl x:Class="SilverLightMasterPageTest.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:SilverLightMasterPageTest">
    <Grid x:Name="LayoutRoot" Background="#FF5C7590">
        <Grid.RowDefinitions>
            <RowDefinition Height="30" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Border Grid.Row="0" CornerRadius="10" Background="#FFDEDEDE" Margin="2,2,2,2" Padding="10,2,10,2">
            <TextBlock Text="Master Page Test" VerticalAlignment="Center" Foreground="#FF14517B" />
        </Border>
        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="110" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <local:NavBar Grid.Column="0" />
            <!-- This canvas is what we change -->
            <Canvas x:Name="ContentHolder" Grid.Column="1">
                <local:Page1 />
            </Canvas>
        </Grid>
    </Grid>
</UserControl>

We need to use a Canvas because it has the Children property that allows us to add / remove child controls. This code shows how to use the Children property to change the page.

Partial Public Class Page
    Inherits UserControl

    Public Sub New()
        InitializeComponent()
    End Sub

    Public Sub ChangePage(ByVal newPage As UserControl)
        ' Removes the currently displayed page
        ' (including from memory)
        Me.ContentHolder.Children.RemoveAt(0)
        ' Adds our new page
        Me.ContentHolder.Children.Add(newPage)
    End Sub
End Class

The Remove option gets rid of the currently displayed control while Add shows the new control. Now all we need to do is have our navigation bar create the correct control and call ChangePage. This is encapsulated in PagePicker (in the code behind for NavBar).

' Encapsulate the logic to select
' the page to display
Private Sub PagePicker(ByVal pageId As PageIds)
    ' Make sure this goes to the top page so that you can get
    ' to your change method.
    ' We're nested in two grids at this point so we need
    ' to go back up the tree.
    Dim pg As Page = CType(CType(Me.Parent, Grid).Parent, Grid).Parent
    Dim newPage As UserControl = Nothing
    Select Case pageId
        Case PageIds.Page1
            newPage = New Page1
        Case PageIds.Page2
            newPage = New Page2
        Case PageIds.Page3
            newPage = New Page3
        Case PageIds.Page4
            newPage = New Page4
    End Select
    ' This is where the actual change
    ' occurs.
    pg.ChangePage(newPage)
End Sub

Private Sub Page1Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    PagePicker(PageIds.Page1)
End Sub

Private Sub Page2Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    PagePicker(PageIds.Page2)
End Sub

Private Sub Page3Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    PagePicker(PageIds.Page3)
End Sub

Private Sub Page4Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    PagePicker(PageIds.Page4)
End Sub

' Just makes it easy to identify
' our pages
Private Enum PageIds
    Page1
    Page2
    Page3
    Page4
End Enum

Notice that PagePicker has to get a reference to the top control so that it can call ChangePage. This will probably be one of the things that bites you as you change the layout. Here's the XAML for NavBar and one of the pages.

<UserControl x:Class="SilverLightMasterPageTest.NavBar"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
    <Border CornerRadius="10" Background="#FFDEDEDE" Width="110" Padding="4,4,4,4">
        <StackPanel>
            <Button x:Name="Page1Button" Content="Page 1" Foreground="#FF14517B" 
                BorderThickness="0" BorderBrush="#FFDEDEDE" Click="Page1Button_Click" />
            <Button x:Name="Page2Button" Content="Page 2" Foreground="#FF14517B" 
                BorderThickness="0" BorderBrush="#FFDEDEDE" Click="Page2Button_Click" />
            <Button x:Name="Page3Button" Content="Page 3" Foreground="#FF14517B" 
                BorderThickness="0" BorderBrush="#FFDEDEDE" Click="Page3Button_Click" />
            <Button x:Name="Page4Button" Content="Page 4" Foreground="#FF14517B" 
                BorderThickness="0" BorderBrush="#FFDEDEDE" Click="Page4Button_Click" />
        </StackPanel>
    </Border>
</UserControl>
<UserControl x:Class="SilverLightMasterPageTest.Page1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot">
        <Border CornerRadius="10" Background="AliceBlue" Width="300"
         HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10,10,10,10" Padding="5" >
            <TextBlock Text="This is page 1" FontSize="22" />
        </Border>
    </Grid>
</UserControl>

Comments

This comment has been removed by the author.
good approach m8, there are is also a solution to this problem by another fellow here
pooran said…
Nice.. found it useful. Do you twitter?
Thanks, pooran! As for tweeting, that's one of my goals for this month. At least three tweets a day. You can find me at http://twitter.com/paulgbrown
Thanks Konstantinidis and sorry for the late post. I thought I had replied when you posted but apparently not!
Bharat said…
i am getting error in the line "Dim pg As Page = CType(CType(Me.Parent, Grid).Parent, Grid).Parent
"Cannot implicitly convert type 'System.Windows.DependencyObject' to 'LibraryMan.Page'. An explicit conversion exists (are you missing a cast?).

Please suggest me.. pls pls......
Bharat, do you mean Library.Main.Page or actually LibraryMan.Page? Also, what version of SL are you working with? I've pretty much moved to the navigation stuf in SL 3 & 4.

Popular posts from this blog

Migrating Legacy Apps to the New SimpleMembership Provider

Asp.Net MVC4 uses the new SimpleMembership provider, changes the table structure and adds a new hashing algorithm. The reasons for the changes can be found in this article by Jon Galloway. This article shows how to migrate your existing apps to the new provider.I’m assuming that you stored your passwords in the unrecoverable SHA-1 format. If you didn’t, then you’ll have to change a couple of things. All of my apps are done this way so… I’m also assuming that you have created the basic skeleton of the new app and ran it once so the correct tables will be created.First, we’ll look at the new tables. Previously, we had all of those aspnet_xxxxxx tables. Here’s the new ones.UserProfileContains all of the elements relevant to the user. This is a combination of the aspnet_Users table and the aspnet_Profiles table.webpages_MembershipStores the password info when not using OAuth, Live, Facebook, etc. This table is somewhat of a match to the aspnet_Membership table.webpages_OAuthMembershipStor…

JavaScript function to automatically add slashes to date

In converting an old Windows app to a browser app, the user wanted to be able to enter dates without the slashes. Here's a simple jscript: 1:// Function to convert short date string (MMddyy) 2:// or (MMddyyyy) to a date string (mm/dd/yyyy). 3:// txtBox is the actual textbox control 4:// with the value to be processed. 5:function FixShortDate(txtBox) { 6:if (txtBox == null) { 7:return'' } 8: 9:var re = new RegExp(/(\d{6})(\d{2})?/); 10: 11:if (re.test(txtBox.value)) 12: { 13:if (txtBox.value.length == 8) { 14: txtBox.value = txtBox.value.substring(0, 2) + '/' + txtBox.value.substring(2, 4) + '/' + txtBox.value.substring(4, 8) 15: } 16: 17:if (txtBox.value.length == 6) { 18:if (txtBox.value.substring(4, 6) < 20)

Get Asp.Net Profile properties from Sql

Ever wanted to include the profile information from an Asp.Net profile in a query? It’s not that hard once you understand the structure. I’ve written a little function that does all the work. Note: I’m using Sql Server as my repository.

First we need to understand how the profile data is stored. Looking at the aspnet_Profile table, we can see that it stores the information in two columns: PropertyNames and PropertyValuesString.

Looking at PropertyNames we can see that it has a basic structure of Property Name, Data Type, Starting Position and Length. For example, in the string “FirstName:S:0:4:Phone:S:4:10:LastName:S:14:5:” we can see that FirstName is of type string, starts at position 0 and has a length of 4. Notice the zero base for the starting position, we need to correct for that in our function. This means in the PropertyValuesString “John2175551212Smith”, we would start with the first position and proceed 4 characters to get the name.

You might be thinking …