One of the guys on the official Silverlight community forums posted an interesting question, namely how does one change the currently visible UserControl in a Silverlight 2.0 application. To put things in context the new Silverlight 2.0 project template creates two classes for you: a System.Windows.Application derived class named App with the associated App.xaml and App.xaml.cs files; as well as a System.Windows.Controls.UserControl derived class called Page with the associated Page.xaml and Page.xaml.cs files.
The App class takes care of the initialization and basically you assign a new instance of your Page class to the App.RootVisual property and through the power of Silverlight it appears on your screen. 🙂
So if you wanted to change the currently displayed UserControl for another instance naturally you’d try and set the App.RootVisual property to another instance of a UserControl. This sounds great in theory but it seems that its a single assignment property. Pete Brown’s blog post happens to make mention of this.
So in a quest to solve the problem I’ve implemented a very simple UserControlContainer class that allows the developer to switch controls at runtime without having to deal with the set once RootVisual property.
Simply create a new UserControl called UserControlContainer and copy the following into the UserControlContainer.xaml.cs file:
public void SwitchControl(UserControl newControl) { LayoutRoot.Children.Clear(); if (newControl != null) { Height = newControl.Height; Width = newControl.Width; LayoutRoot.Children.Add(newControl); } }
Next set your Application instance RootVisual to an instance of the new UserControlContainer in the Application_Startup method.
private void Application_Startup(object sender, StartupEventArgs e) { // Load the main control this.RootVisual = new UserControlContainer(); Page page = new Page(); ((UserControlContainer)this.RootVisual).SwitchControl(page); }
Then wherever you need to switch out the active control, simply call the following if you are inside App.xaml.cs:
TestControl1 testControl = new TestControl1(); ((UserControlContainer)this.RootVisual).SwitchControl(testControl);
Or the following if you need to switch controls from elsewhere:
TestControl1 testControl = new TestControl1(); ((UserControlContainer)Application.Current.RootVisual).SwitchControl(testControl);
If you find this useful or find any issues with this method, let me know so I can improve it for all.
Updated 2008-03-13: Added Application_Startup example. Thanks to Maurice for pointing this omission out.
[tags]Silverlight 2.0,code,example[/tags]
You might want to add the following piece of code to your post to document how to make this run:
private void Application_Startup(object sender, StartupEventArgs e)
{
// Load the main control
this.RootVisual = new UserControlContainer();
Page p = new Page();
((UserControlContainer)this.RootVisual).SwitchControl(p);
}
@MauriceD: Thanks I’ll update accordingly.
Thanks a lot! This is what I need!
This was very helpful to me. Just the simple and elegant page switching approach I needed.
How to hold the state of page when switch back
from testControl
It works really well! Thank you 🙂
Great post, how do I update switch the control if I want to update the Silverlight Control from the hosting web page? I have a .aspx page and based on a selection that a user makes, I want to change the Silverlight control to be displayed. However in the .aspx.cs I don’t have access to the UserControlContainer.
THIS STINKS HOW DO U SWITCH USERS
I did this using startup params.
The “flow” goes something like this :
1. User requests page so server builds page
2. server sends page to client and client scripts execute
3. silverlight objects are executed
So …
In your aspx page html you put the standard object tag with this in it :
depending on requirements you can either edit this object tag on the server or the client.
1 Of the params I pass in is a “StartingControl” which in the App.Xaml.cs file I do this with :
void Application_Startup(object sender, StartupEventArgs e)
{
switch(e.InitParams[“StartupControl”])
{
case “Control1” :
this.RootVisual = new Control1();
break;
….
}
}
This gives you switching functionality before the silverlight object is loaded.
Combine the 2 samples and you can make whatever changes you need at any point.
🙂
In an application with – say 1000 – pages, do all of these pages get streamed to the client (browser), or just the currently visible page?
Well if by “pages” you mean Silverlight canvases/controls, then yes, they all get packaged in your XAP file and sent to your browser at the same time. Using Silverlight 3 though you can do some more interesting deferred loading of resources.
The InitParams solution is good for views that only change when the web page is refreshed. My solution is for when you need to keep a long-runnning instance of the same control.
It depends how you implement your concept of a user. If you are using the commonly used cookie-based forms authentication scheme then you could make a Web service call to a logout/login method and change user that way.
Useful indeed…Thanks very much!
Oh my god that is the most useful thing Ive ever found on
the internet!! Thankyou. Your neat little fix just made my
coursework work!!
Nice One! Saved lot of Time!
How about just clear and add the children collection
directly in the transfer event like private void
cmdSLControl_Click(object sender, RoutedEventArgs e) {
LayoutRoot.Children.Clear(); LayoutRoot.Children.Add(new
SilverlightControls());
//((UserControlContainer)Application.Current.RootVisual).SwitchControl(new
SilverlightControls()); }
Just call this function with required page u want load…. dats it
public void SwitchControl(UserControl newControl)
{
LayoutRoot.Children.Clear();
LayoutRoot.Children.Add(newControl);
}
This is a useful post.Can you explain me switching rootvisuals between silverlight test project and silverlight3 main project.If i try this i get an error
Unable to cast object of type ‘Microsoft.Silverlight.Testing.UnitTesting.UI.TestPage’ to type ‘com.bgt.li.UserControlContainer’.
Thanks a lot!!!
Best solution ever seen thanks