Thanks for visiting my blog! See more about me here: About Me
Url: http://slextensions.codeplex.com
As some of you may know, I am a contributor to the SilverlightContrib open source project. Recently this project and the Silverlight Extensions open source project (also know as SLExtensions) decided to merge to create a single place for a lot of interesting functionality.
I want to highlight some of the pieces that I didn’t contribute as I’ve seen a lot of really great functionality for those of you who are building Silverlight Applications. I honestly have no idea how many parts this blog series will be, as long as I have parts that are interesting, I’ll continue to post about them.
First up is SLExtension’s Bootstrapper functionality. If you are currently using Prism or a related technology to compose your application at runtime, this functionality is lost on you. The Bootstrapper functionality is for that middle-ground where you want to break up your project into a small number of .xap files that are loaded when the project loads up but don’t need a full composition engine with MEF or Prism.
The Bootstrapper functionality is in a separately assembly in the SLExtensions project (SLExtensions.Bootstrapping.dll). This is a small assembly (so that your main project loads fast). The way it works is to have you change the derived class for the App.xaml to a BootstrapApplication:
public partial class App : BootstrapApplication
{
Since its the App.xaml class, you’ll need to change the XAML as well:
<bs:BootstrapApplication
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="FunWithBootstrapper.App"
xmlns:bs="clr-namespace:SLExtensions.Bootstrapping;
assembly=SLExtensions.Bootstrapping">
<bs:BootstrapApplication.Resources>
</bs:BootstrapApplication.Resources>
</bs:BootstrapApplication>
Once you have the application changed, you will need to override the Xaps property to supply the list of XAP files to load:
protected override IEnumerable<Uri> Xaps
{
get
{
// Must be absolute Uris so we steal it from the host
return new Uri[] {
new Uri(new Uri(Host.Source.AbsoluteUri), "SecondApp.xap"),
new Uri(new Uri(Host.Source.AbsoluteUri), "ThirdApp.xap"),
};
}
}
At this point it will load up the other .xap files but we won’t be able to do anything with them. So let’s look at the other projects briefly.
The other Silverlight projects are actually full Silverlight Applications (not Client Library projects). The Bootstrapper is usually used to create a ‘splash screen’ xap file that loads the other parts of the applications. Again, not real composition like Prism, but something less than that.
In the main project, you will make a reference to the other application projects. That’s how you’ll be able to reference the code from the other xap files (though only once they’ve been loaded).
To help you know when its updated, the Bootstrapper application has two facilities:
- Progress event
- OnApplicationReady overridable method
Now that you have a bootstrapping application, you want to be able to work with it. The first thing I usually do (because I want to use the Bootstrapping API’s from anywhere without casting) is create a new static property on the Application class:
// Better access to the bootstrapping app
public static App MyApp
{
get { return Current as App; }
}
Then I can use the Progress event to show the user some progress like so:
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
App.MyApp.Progress +=
new EventHandler<BootstrapEventArgs>(Bootstrap_Progress);
}
void Bootstrap_Progress(object sender, BootstrapEventArgs e)
{
thePartProgress.Value = e.StepProgress;
theFullProgress.Value = e.OverallProgress;
}
I’d like to be able to know when the application is completely loaded too. Unfortunately the Progress event tends to not return 100% at any time. I haven’t figured out why yet, but to get around that you can use the OnApplicationReady overridable method:
public partial class App : BootstrapApplication
{
...
protected override void OnApplicationReady(StartupEventArgs e)
{
// Do startup behavior
}
...
}
While this works, I often don’t want to do this work in the App class, but instead in other parts of my application (e.g. MainForm.xaml.cs). So For my use, I usually expose an event as well:
public event EventHandler<StartupEventArgs> StartupComplete;
protected override void OnApplicationReady(StartupEventArgs e)
{
if (StartupComplete != null)
{
StartupComplete(this, e);
}
}
By throwing an event when the application is ready, I can register for this event and do the startup once I know all the code is available:
// MainPage.xaml.cs
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
App.MyApp.Progress +=
new EventHandler<BootstrapEventArgs>(Bootstrap_Progress);
App.MyApp.StartupComplete +=
new EventHandler<StartupEventArgs>(Bootstrap_StartupComplete);
}
void Bootstrap_StartupComplete(object sender, StartupEventArgs e)
{
// Use the loaded types
// (SecondApp.MainPage and ThirdApp.MainPage)
theSecondApp.Children.Add(new SecondApp.MainPage());
theThirdApp.Children.Add(new ThirdApp.MainPage());
}
Note that once the bootstrapping has completed you can use the assemblies in the other .xap projects. If you attempt to use them before, you’ll get an exception that it couldn’t load the type.
Just to prove the point, here is a list of the .xap files. Notice that the 2nd and 3rd .xap file are pretty big but even with the bootstrapping assembly, our code is only 10K which means it should load very fast:
Neat? What do you think?
You can get the source to my example here:
http://wilderminds.blob.core.windows.net/downloads/FunWithBootstrapper.zip