Page view counter

Multi-Page Applications in Silverlight

I wanted to build a multi-page (Search - Results) application when I realized that isn't really our model. Fortunately, I wrote to Ashish Shetty , who combines enormous knowledge with enormous kindness, and even though he is in the middle of blogging about this, he agreed that I could blog about it as well. Since I will be creating an HDI Video on this as one of my first Beta 2 videos (RSN) and since I think his solution is wicked cool, here is how you do it

1. Create a new Silverlight 2 project in Visual Studio , (I named mine, MultiPage).

2. You want to have at least three pages. Let's use the default Page.xaml as the first. Add any content you like but  but include a button with a name and set the content to something like "Switch"

3. Right click on the project and click Add New Item, and add a second User Control. Name the new user control anything you want and give it any content you want. I'll call mine Page2.xaml and give it content to make it distinct: 

<UserControl x:Class="MultiPage.Page2"
    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" Background="Beige">
        <StackPanel Orientation="Horizontal">
        <TextBlock Text="This is Page2" FontFamily="Comic Sans MS" 
            FontSize="48" VerticalAlignment="Center" />
        <Button x:Name="SwitcherooButton" Content="Switcheroo" 
            Height="40" Width="80" 
            Background="Red" FontSize="14" 
            Margin="20,0,0,0" />
        </StackPanel>
    </Grid>
</UserControl>

 

Page2Switcher

Note that again I have a button for switching pages.

 

Here is where the magic happens

4. Add a third page (I named mine PageSwitch.xaml.)  Put nothing in the xaml file, because the content will be the page you want to display,  but in the code-behind file add this method:

public void Navigate(UserControl nextPage)
{
    this.Content = nextPage;
}

5. Wire up the buttons on all of your pages to invoke the Navigate method, passing in the page you want to navigate to.

So, in Page.xaml.cs you'll add this code,

public Page()
{
    InitializeComponent();
    SwitchButton.Click +=
          new RoutedEventHandler(SwitchButton_Click);
}
 

void SwitchButton_Click(object sender, RoutedEventArgs e)
{
    PageSwitcher ps = this.Parent as PageSwitcher;
    ps.Navigate(new Page2());
}

 

6. Finally, in App.xaml.cs change the startup page from Page.xaml to PageSwitcher.xaml,

 private void Application_Startup(object sender, StartupEventArgs e)
 {
     this.RootVisual = new PageSwitcher();
 }

 

What's Going On Here??

The way this all works is that when your program starts, the opening page is now PageSwitcher whose content is blank, but whose constructor sets it to whatever you want your first page to be (in this example,  Page.xaml.)  Since all pages are actually user controls, they work fine as the content of a page.

When you click the switch button, you find the parent of your page which is the PageSwitcher page and that has a Navigate method that you invoke, passing in the page you want to navigate to. In this case, we're hardwiring the change, but it wouldn't be hard to make that value be more dynamic.

Navigate causes the PageSwitcher page to change its contents from whichever page it is currently displaying to whichever page you ask it to display, and the garbage collector cleans up the old.

(If you need to keep old values around between switches, create both pages and don't call new, but that will use more memory, or stash the values you need inside member variables of PageSwitcher -- more on that when I do a video on this approach).

 

It is a very cool, very fast effect switching from one page to the other.

SwitchToPage1 SwitchToPage2

 

Here's the complete source code

Published 31 May 2008 10:40 AM by jesseliberty

Comments

# BenHayat said on 31 May, 2008 01:47 PM

Great blog Jesse.

One minor typo. You wrote:

>>4. Add a third page (I named mine PageSwitch.xaml.)<<

That should be "PagerSwitcher.xaml" to match the codes you wrote in the bottom.

I had been playing with this concept and now I have two styles/models of Page programming. One that works like WinForm "Modal" type, where you go down into inner pages and then you back out and all the child pages can see their parents data. And as you backout, you remove the page from the parent collection, where the memory gets released.

The second one (as you demonstrated) works in sequential model like Web Pages where there is only one page active at a time. But the developer must create some sort of "Master menu" that would allow the user to jump anywhere.

Question: When this command is executed "ps.Navigate(new Page2())", what's going to happen to the previous pageSleep that had been created in the memory. I'm concern about that.

Thanks!

# jesseliberty said on 31 May, 2008 02:02 PM

>>what's going to happen to the previous page that had been created in the memory<<

There no longer being a reference to it, it will be cleaned up by the garbage collector. The idea of this approach is that it uses less memory; as you replace the content, you replace the memory usage.

# Wounded_Ego said on 31 May, 2008 07:30 PM

Thanks, this looks like it will be useful.

However, I'm not the brightest bulb in the marquee, I'm afraid, so maybe you can help me with something...

You supplied all the source code, but no solution or project file. How do I handle that in VS2008? I can create a blank solution but how do I create a blank project in which to host this?

Thanks,

# jesseliberty said on 31 May, 2008 08:48 PM

>>You supplied all the source code, but no solution or project file. How do I handle that in VS2008? I can create a blank solution but how do I create a blank project in which to host this?<<

I'm sorry, I should have explained.  This is important enough that I'll answer in a new blog post.

Thanks!

# nexus888 said on 01 June, 2008 03:32 AM

I tried to change your example to assign the pages to the visualroot element of the App class, but it didn't work. Instead it would keep pointing to the initial page that was assigned to it.

Would you know why this is the case?

# jesseliberty said on 01 June, 2008 07:46 AM

Yes, the documentation points out that you can only assign to the visual root once.

-j

# Dew Drop - June 1, 2008 | Alvin Ashcraft's Morning Dew said on 01 June, 2008 09:59 AM

Pingback from  Dew Drop - June 1, 2008 | Alvin Ashcraft's Morning Dew

# Blogs said on 02 June, 2008 12:56 AM

I posted the code for the PageSwitcher app described in a previous blog post , but to save space and

# Weekly Links: ASP.NET MVC, .NET, ADO.NET Data Services … said on 02 June, 2008 04:45 PM

Pingback from  Weekly Links: ASP.NET MVC, .NET, ADO.NET Data Services &#8230;

# Microsoft Weblogs said on 08 June, 2008 10:05 PM

Pages as a paradigm likely pre-date the web itself although they have been popularized by document-based

# Suprotim Agarwal said on 25 June, 2008 06:02 AM

Pingback from :

How to Navigate and Pass Values between Pages using Silverlight 2 Beta 2

at

www.dotnetcurry.com/ShowArticle.aspx

# matt_stephens said on 30 June, 2008 07:34 AM

Pages aren't garbage collected!

I just created a small sample based on this to test that the garbage collector does reclaim the page but it appears not to until the browser is closed.

I added a finalizer to one of my pages and put a breakpoint in it. On one of the other pages i call GC.Collect() after calling the Navigate method. No matter how many times i cycle round different pages i never see the finalizer run but as soon as i exit the browser the finalizer runs for every instance of the page that i created.

In Ashish Shetty's article all pages are created up front and i wonder if this is the reason? We want to write an application that could potentially be running for a very long time so to know that the garbage collector is working properly and we're not going to consume loads of memory is very important to us.

# jesseliberty said on 30 June, 2008 11:31 AM

Matt, you are absolutely correct. After talking with Ashish (who is truly a generous and smart person) and revisiting my code:

1. The way I am doing it is by having references in each page to the other, (much like WPF’s navigation model, the “navigate by object” pattern) which does allow for creating retrievable state but is not what I intended.  

2. There is an obvious alternative (using "navigate by reference") that I will demonstrate in an upcoming video (a few weeks).

Thanks for pointing this out.

# matt_stephens said on 30 June, 2008 12:40 PM

Could you elaborate on what you mean by 'navigate by reference'?

I never downloaded your code, only read the article and implemented a quick test. I am not maintaining any references from any of my page classes to the ones i navigate to so i can only assume it's the underlying handling of objects within silverlight that is stopping my 'pages' from getting garbage collected.

Thanks for any help. Look forward to the video.

# Michael Sync » 10 Silverlight 2 gotchas resolved: By Antoni Dol said on 19 July, 2008 03:20 AM

Pingback from  Michael Sync  &raquo; 10 Silverlight 2 gotchas resolved: By Antoni Dol

# Craig Shoemaker said on 29 August, 2008 12:18 PM

Listen to the Show! Jesse Liberty the "Silverlight Geek" wants to help you dive deeper into Silverlight

# Recent Faves Tagged With "multipage" : MyNetFaves said on 01 October, 2008 07:20 AM

Pingback from  Recent Faves Tagged With "multipage" : MyNetFaves

# donmarais said on 27 October, 2008 03:36 PM

How will the implementation change for SL2 RTW?

I'm having a problem with the navigation function.

void Switch_Click(object sender, RoutedEventArgs e)

       {

           PageSwitcher ps = this.Parent as PageSwitcher;

           ps.Navigate(new Video());

       }

For some reason, I'm getting an error on my button switch click. Object reference not set to an instance of an object.

It worked in SL2B2, but now I'm having hassles to implement.

# Bryant Likes's Blog said on 22 December, 2008 11:16 PM

qingquan126778 asked the question in the Silverlight forums about how to switch between pages in Silverlight

# gthardy said on 28 December, 2008 08:28 AM

I am having a similar issue as donmaris;

"Object not set to an instance of an object". at this point in the code

ps.Navigate(new Page2());

Any ideas on why this may occur with SL2?

# gthardy said on 03 January, 2009 07:32 PM

PageSwitcher pageSwitcher = new PageSwitcher();

This solved my object not set to instance issue.

# RenyCaine said on 05 January, 2009 06:54 AM

Any lead on how to navigate pages in 1 xaml page?

i visited the Silverlight forums, nobody give the right lead.

# Silverlight Travel » Switching XAP Files on the Client Side said on 24 January, 2009 04:18 AM

Pingback from  Silverlight Travel &raquo; Switching XAP Files on the Client Side

# mehtapratik said on 19 June, 2009 07:48 AM

Can anyone implemented this so that application performance is not affected??