Way back in July, shortly after Silverlight 3 was released, I posted a technique that allowed you to use the Navigation framework in the SDK to load pages in dlls that would be downloaded as part of the navigation process. The solution relied on two things: a workaround to the navigation framework’s inability to navigate to Pages in dynamically-loaded assemblies, and a derived version of the Frame class that hid many methods in order to orchestrate downloads of dlls and their dependencies.
With Silverlight 4’s INavigationContentLoader extensibility point, we can address this scenario much more effectively, and are no longer locked into the workarounds and strict constraints that Silverlight 3’s navigation feature placed on us. In this post, I’ll walk through the use of another ContentLoader I’ve been working on and look at how it simplifies building multi-xap applications.
Getting a jump-start
If you’d like to get started quickly and see the magic of multi-xap applications, follow these steps (note: Requires the Silverlight 4 Beta and an active internet connection) or download the source for the steps below here (you may need to fix up the references after downloading SLaB):
- Download and extract SLaB
- Open Visual Studio 2010 and create a new Silverlight 4 project using the Silverlight Navigation Application template. When prompted to create a corresponding ASP.NET web application, just click “OK” and let Visual Studio create a web project for you.
- Add a reference to SLaB.Navigation.ContentLoaders.Xap.dll from the extracted Binaries folder.
- Add the following line of code to App.xaml.cs: PackUriParser.Initialize();
- Replace the Frame in MainPage.xaml with the following code (new code is bold/italic– the rest is identical to the default project xaml except for formatting):
<navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}" Source="/Home" Navigated="ContentFrame_Navigated" NavigationFailed="ContentFrame_NavigationFailed"> <navigation:Frame.UriMapper> <uriMapper:UriMapper> <uriMapper:UriMapping Uri="" MappedUri="/Views/Home.xaml" /> <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml" /> </uriMapper:UriMapper> </navigation:Frame.UriMapper> <navigation:Frame.ContentLoader> <SLaB:XapContentLoader xmlns:SLaB="clr-namespace:SLaB.Navigation.ContentLoaders.Xap;assembly=SLaB.Navigation.ContentLoaders.Xap" EnableCrossDomain="True" /> </navigation:Frame.ContentLoader> </navigation:Frame>
- Run the application.
- Replace “#/Home” in your browser’s address bar with “#pack://http:,,open.depoll.com,SimpleApplication,SimpleApplication.xap/SimpleApplication;component/Depoll.xaml?Source=http://open.depoll.com&File=wildlife.wmv”
- Wait for a moment, and then enjoy the (admittedly underwhelming) show!
Whoa, what just happened?!
You just created an application that loaded a page in another xap! It took only two actions to make this happen: registering the “PackUriParser” and setting the Frame’s ContentLoader to a XapContentLoader with cross-domain access enabled. When you added the “pack://…” to the browser’s address bar, you told the content loader to downlaod a xap at http://open.depoll.com/SimpleApplication/SimpleApplication.xap (which is on my personal site, and has a very permissive cross-domain policy) and load the page “Depoll.xaml”.
The XapContentLoader makes loading pages in other xaps (and reducing your download sizes) as easy as coming up with a URI that points to the page. Read on to learn more about how to use the XapContentLoader and some of the problems associated with multi-xap applications.
Why load pages in external xaps?
This has always been a particularly interesting scenario to me. The size of your application’s xap file can have a big impact on your users’ experience with your Silverlight application. Since the entire xap and its dependencies (e.g. cached assemblies) must download before users can interact with your application, keeping the xap’s size small means users can start using your application sooner and are less likely to give up and click away.
Partitioning your application into smaller-sized chunks that download only when users attempt to access that piece of functionality can also save bandwidth (since users need not download parts of the application they won’t use).
The folks behind both MEF (Package catalogs) and Prism (Modules) have great libraries that help you accomplish this partitioning. To me, navigation is a natural delineator of application functionality – Pages represent pieces of functionality your users can access, so triggering loading of other assemblies/xaps as part of navigation means that users will get the pieces of the application when they want to use them.
In this post, I will be outlining a XapContentLoader, which makes loading pages in other Xaps a 2-lines-of-code problem to solve. I’ve added this ContentLoader and some related utilities to SLaB, so you can use it yourself or play with the code if you like!
XapLoader
The first component I needed to make this scenario work was a way to download and load xap files. As such, I wrote a XapLoader utility. The strategy I used for loading xaps was the following:
- Download the xap
- Read the AppManifest.xaml within the xap to locate the assemblies therein
- Load all assemblies within the xap
- Download zip files for the “ExtensionParts” within the AppManifest (used for the “cached assemblies” feature)
- Load the assembly associated with each zip file
Why worry about ExtensionParts? My hope is to use this feature to solve the shared dependency problem. For example, the System.Windows.Controls.Data.dll file in the SDK (containing the DataGrid control) is a fairly large assembly (446 kb uncompressed). I’d like to avoid having users download this assembly when the app first loads, so I partition my application into four xaps: Main.xap, Foo.xap, Bar.xap, and Baz.xap. Foo.xap and Bar.xap both use the DataGrid control. Since I have no guarantees about the order in which my users will access the application, I need to make sure both of those xaps have access to that assembly, so I partition my application as follows:
This is a bit painful, since now when I download both Foo.xap and Bar.xap, I’m forced to download System.Windows.Controls.Data.dll twice! Instead, if I turn on the assembly caching feature introduced in Silverlight 3, I can get both Foo.xap and Bar.xap to point to the same System.Windows.Controls.Data.dll. By taking it out of the actual xaps and making it a separate download, I need only download it once (in fact, the browser’s cache will take care of it for me!). Now, my application is partitioned in this way:
And now I’ve effectively partitioned the application without keeping redundant libraries around that would increase the overall download size of the application.
My implementation allows you to do this (using the same mechanism as “assembly caching”), but has the following limitations:
- Cached assembly .zip files must contain only one assembly per zip.
- The name of the .zip file must be the same as the assembly name (replacing “.dll” with “.zip”)
This loader returns a “Xap” object, which has all of the loaded assemblies related with the xap, a “Manifest”, which contains the same data as the Deployment defined in AppManifest.xaml within the xap, and a means to get the original streams from which each assembly was loaded (for use in keeping local copies, if that’s what you’d like to do). The XapContentLoader, described below, uses this loader to find and load xaps that would contain additional pages.
XapContentLoader
The XapContentLoader is an implementation of INavigationContentLoader that will download an external xap and load a page in one of its assemblies. This content loader uses a slightly modified version of the pack uri scheme (which I’m probably abusing a bit here, but oh well
). Technically, it only takes two lines of code/XAML to use the XapContentLoader:
First, add the following line to your Application’s startup code (usually in App.xaml.cs), which registers the pack uri scheme with the built-in Uri class, so that you can create pack Uris in code and XAML without having exceptions be thrown:
PackUriParser.Initialize();
Then, in XAML:
<navigation:Frame x:Name="ContentFrame" Source="/Views/Home.xaml"> <navigation:Frame.ContentLoader> <xapLoader:XapContentLoader /> </navigation:Frame.ContentLoader> </navigation:Frame>
And that’s it! Alright, that’s all. See you later…
…
…
…
Ok, ok, I won’t leave you hanging like that! Let’s look at how you would now use this content loader to load a page in another xap. First, a quick review of the pack uri scheme as I understand it:
pack://<authority>/<path>
There are three parts to this Uri:
- “pack://” – this is the scheme name of the Uri. All absolute pack Uris begin with this.
- “<authority>” – this is actually another Uri (just replace “/” with “,” and escape any other necessary characters). For the XapContentLoader, this is a path to some xap. For example, I might use the following authority: “http:,,www.davidpoll.com,xaps,MyApplication.xap”. This indicates that I’ll be loading a page within the xap at that location. I also support two other “special” authorities: “application:///” and “siteoforigin://”. “application:///” cannot have an additional path attached to it, since I translate this as the location of the initial xap from which the application was loaded. It’s basically equivalent to Application.Current.Host.Source. “siteoforigin://” is replaced with the directory from which the application’s xap was loaded. As such, any of the following authorities would be valid:
- http:,,www.davidpoll.com,xaps,MyApplication.xap
- https:,,www.davidpoll.com,securexaps,MySecureApplication.xap
- application:,,,
- siteoforigin:,,MyApplication.xap (equivalent to the first item in this list if MyApplication.xap was the entry point xap)
- “<path>” – this is the path within the xap. Usually, this looks like: “/SomeLibrary;component/Views/Page1.xaml”. If no assembly name is provided, I assume they are referring to the “EntryPointAssembly” referred to in the AppManifest.xaml file of the xap.
Some examples of valid Uris to navigate to (all equivalent assuming MyApplication.xap was the initial xap):
- /Views/Page1.xaml
- pack://application:,,,/Views/Page1.xaml
- pack://application:,,,/MyApplication;component/Views/Page1.xaml
- pack://http:,,www.davidpoll.com,xaps,MyApplication.xap/Views/Page1.xaml
- pack://http:,,www.davidpoll.com,xaps,MyApplication.xap/MyApplication;component/Views/Page1.xaml
- pack://siteoforigin:,,MyApplication.xap/Views/Page1.xaml
- pack://siteoforigin:,,MyApplication.xap/MyApplication;component/Views/Page1.xaml
Unfortunately, coming up with these Uris can be a bit of a pain, so I’ve provided a custom type of UriMapping that works on a per-xap basis to make this simpler:
<navigation:Frame.UriMapper> <navUtils:UriMapper> <xapLoader:PackUriMapping XapLocation="siteoforigin://TernaryXap.xap" Uri="/remote/{assemblyname}/{path}" MappedPath="/{path}" /> </navUtils:UriMapper> </navigation:Frame.UriMapper>
Now, I needn’t ever actually write a pack uri myself. Instead, I can have hyperlinks like “/remote/TernaryXap/Views/Page1.xaml”, and these mappings will generate the appropriate pack uris for you. They work just like the UriMapping built into the SDK in terms of replacing values in the MappedPath. “{assemblyname}” is a special token (that you could omit if you set the PackUriMapping.AssemblyName property) that allows you to make the assembly name part of your path.
Enhancing the experience
Great, so now we’ve got navigation integrated with on-demand xap loading. It takes very few lines of code, and is quick to set up. Note that my xaps have no concrete knowledge of one another (even the hyperlinks are just text, and users could manually enter other hyperlinks). But web requests are slow, and could fail. How can we improve the experience around this type of navigation?
Well, I’ve got two ideas for you that you might recognize: BusyIndicator and ErrorPageLoader.
Since web requests can fail (lost connectivity, bad links, servers being down, or other random problems), we should make sure users don’t see exceptions under those circumstances. For this, we’ll whip out the ErrorPageLoader from our trusty utility belt and use it to load a local error page if something goes wrong:
<loaders:ErrorPageLoader> <loaders:ErrorPageLoader.ContentLoader> <xapLoader:XapContentLoader /> </loaders:ErrorPageLoader.ContentLoader> <loaders:ErrorPageLoader.ErrorContentLoader> <navigationLoader:PageResourceContentLoader /> </loaders:ErrorPageLoader.ErrorContentLoader> <loaders:ErrorPage ErrorPageUri="/Views/ErrorPage.xaml" /> </loaders:ErrorPageLoader>
You’ll notice that I’ve used the built-in (SDK) PageResourceContentLoader as my ErrorContentLoader. I did this because, presumably, something bad has happened with the XapContentLoader, so I want to use a ContentLoader with low likelihood of failure in order to display an error page.
Next, users shouldn’t be left hanging while they wait for a link to load. We can use the BusyIndicator control in the toolkit in order to let the user know that something is going on. The XapContentLoader has an “IsBusy” property as well as a “Progress” property. We can make the BusyIndicator’s progress bar display progress and appear by binding it to these properties on the XapContentLoader. The following handy XAML accomplishes this:
<toolkit:BusyIndicator IsBusy="{Binding ContentLoader.ContentLoader.IsBusy, ElementName=ContentFrame}" DisplayAfter="0:0:0.1"> <toolkit:BusyIndicator.BusyContent> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <TextBlock Text="Loading page..." Margin="0,0,0,4" /> <ProgressBar Grid.Row="1" Minimum="0" Maximum="1" Height="25" Value="{Binding ContentLoader.ContentLoader.Progress, ElementName=ContentFrame}" /> </Grid> </toolkit:BusyIndicator.BusyContent> <toolkit:BusyIndicator.ProgressBarStyle> <Style TargetType="ProgressBar"> <Setter Property="Visibility" Value="Collapsed" /> </Style> </toolkit:BusyIndicator.ProgressBarStyle> <navigation:Frame x:Name="ContentFrame" Source="/Views/Home.xaml"> <navigation:Frame.ContentLoader> <loaders:ErrorPageLoader> <loaders:ErrorPageLoader.ContentLoader> <xapLoader:XapContentLoader /> </loaders:ErrorPageLoader.ContentLoader> <loaders:ErrorPageLoader.ErrorContentLoader> <navigationLoader:PageResourceContentLoader /> </loaders:ErrorPageLoader.ErrorContentLoader> <loaders:ErrorPage ErrorPageUri="/Views/ErrorPage.xaml" /> </loaders:ErrorPageLoader> </navigation:Frame.ContentLoader> </navigation:Frame> </toolkit:BusyIndicator>
Note that I’ve hidden the BusyIndicator’s default progress bar, and added one to its BusyContent that binds to the XapContentLoader’s progress. Now, when users navigate to pages and have to wait for them to load, they are presented with the BusyIndicator and a progress bar letting them know how much is left to be downloaded. The application continues to appear responsive, and users can continue to work with the rest of the application.
Cross-domain considerations and limiting access
We’ve now unleashed a lot of power. Your application can now load pages in any xap that Silverlight can get access to using a WebClient. If the Frame control you’re using integrates with the browser, users can type any uri into the browser to navigate to, and right now, the XapContentLoader will blindly go and load their code.
This could be a bit of a security issue (I’m no expert, but this one sticks out like a sore thumb).
Suppose domain supersecret.com has a cross-domain policy that allows my domain (and only my domain), davidpoll.com, to access services on it. My domain is using the XapContentLoader, and can load pages in any xap that WebClient can access. A developer whose domain is evil.com realizes this, and decides to try to get access to supersecret.com’s services. He’s able to do this by:
- Adding a cross-domain policy that allows davidpoll.com to access xaps on evil.com
- Pointing the Silverlight application on davidpoll.com to his xap on evil.com (this will work, since WebClient just checks evil.com’s cross-domain policy)
- Now that evil.com’s xap has been loaded and is running on davidpoll.com’s application, he can access supersecret.com’s services (since the evil.com’s code is now running on davidpoll.com)!
Because of this problem, I’ve disabled cross-domain loading on the XapContentLoader by default. You can re-enable it, but please be aware of this potential problem. The AuthContentLoader is a convenient way to restrict access to domains you don’t want users to be able to access just by changing the Uri. Here, I’ve enabled cross-domain access, but restricted access only to my other domain (this one happens to be my personal website that I don’t update too often
):
<auth:AuthContentLoader> <auth:AuthContentLoader.ContentLoader> <xapLoader:XapContentLoader EnableCrossDomain="True" /> </auth:AuthContentLoader.ContentLoader> <auth:NavigationAuthorizer> <auth:NavigationAuthRule UriPattern="pack://((siteoforigin:,,)|(authority:,,)|(http:,,open\.depoll\.com)).*"> <auth:Allow Users="*" /> </auth:NavigationAuthRule> <auth:NavigationAuthRule UriPattern="pack://.+:,,.*"> <auth:Deny Users="*" /> </auth:NavigationAuthRule> </auth:NavigationAuthorizer> </auth:AuthContentLoader>
This allows users to access xaps on my site (open.depoll.com), while denying access to other pack uris. Coupled with the ErrorContentLoader, a consistent, safe experience can be provided for users.
MEF and Prism
At this point, you might be asking yourself why I rolled my own solution to this problem? MEF and Prism both have very effective implementations for modularization of applications, and you could certainly build very similar ContentLoaders based upon their libraries for loading xaps (in fact, I hope to see folks out there do so!
). Really, the reason I rolled my own libraries for this is twofold:
- Support for cached assemblies – I wanted to make sure to attempt to solve the shared dependency problem described earlier
- Size – it’s important to keep the size of the bootstrapping assemblies small in order to reap the benefits of dynamic loading. The total size of the libraries required for the XapContentLoader is about 25k compressed. I’d still like to pare that down, so if folks have ideas, let me know
If you’ve got ideas for how best to use MEF or Prism with INavigationContentLoader, let me know! If you’re already using them for modularization and want to integrate them with navigation, this is possible in Silverlight 4 thanks to INavigationContentLoader.
The goods
As you know by now if you’ve been following my blog, I never leave you stranded without code and a live sample! Take a look!
Click around using the links on top and see what happens to the Uri in the browser’s address bar. You’ll note the cross-domain access as well as the use of QueryStrings (which still work, of course!). Open up Fiddler or some other tool to verify that xaps and zip files for cached assemblies are only downloaded once thanks to browser caching. Enjoy it!
Finally, some source code for you:
- For the latest version, please check out SLaB on my Downloads and Samples page.
- The v0.3 download of SLaB includes the following changes:
- Added more extensible UriMapper that replicates the built-in UriMapper’s behavior but allows UriMappings to be more extensible.
- Added UiUtilities, the first of which allows you to execute a function on the UI thread and block the calling thread until it has completed (safe to call even from the UI thread)
- Added XapLoader, which downloads a Xap and any "cached assemblies"
- Added XapContentLoader, which uses the XapLoader to navigate to pages in downloaded assemblies
- Added PackUri utilities so that pack Uris can be used to download and navigate to pages in Xaps
- Signed all assemblies (public binaries use a private key, another key is distributed with source)
- Added a build task that will generate extmap files for all libraries — now assembly caching works with SLaB assemblies
- Fixed a bug with the AuthLoader where all rules would be run, even if one rule already allowed access
- Other minor bugfixes
Enjoy, and let me know if you have any questions, thoughts, or ideas!
Remember, SLaB is just a collection of the samples and experimental components I’ve been putting together so that they’re all in one place. I can’t make any guarantees about maintaining them, fixing bugs, not making breaking changes, etc., but you’re more than welcome to try them out, use them, and let them inspire your development (or show you what not to do if you really dislike something I’m doing!)
.

#1 by Waleed on November 29, 1999 - 4:00 pm
Hello David,
I found your post very promissing to me to start dividing my first SL4 app.
I opened the scratch application and added another SL project that use the same .web page, then i add this URI to a Hyberlink button
“NavigateUri=”pack://siteoforigin:,,SilverlightApplication1.xap/SilverlightApplication1;component/MainPage.xaml” but it doesn’t work I mean I got an empty page … What do I missing here … !!
If you could help on this will be great
Regards
#2 by Waleed on November 29, 1999 - 4:00 pm
Sorry for this, But I found the reason, I didn’t add it to the silverlight projects for the web application.
Can you tell me if this solution (in the scratch application) is a replacment for the one you introduced in the solution introduced in the DynamicXapLoading project, which I realy like as it implements the MVVM in a prety way.
Once agin, thanks for your efforts.
#3 by Waleed on November 29, 1999 - 4:00 pm
Sorry, I post that question in a wrong post
But i have another Question:
I explored the DynamicXAPLoading application and it also load the xap dynamically, should I also used the xaploader or the xaploadercontent, I am a little bit confused ..
Please clarify …
best
#4 by Waleed on November 29, 1999 - 4:00 pm
Hello David,
I try to implement the MVVM & MEF with for the mainpage by creating a ModelView class and using the [import]/[export]. but I fail …
How can this be accomplished by this approach.
Best regards
#5 by Jonathan Perl on February 2, 2010 - 10:53 am
Awesome post!! I was trying to use MEF to do this sort of thing, but this is much more elegant (in my opinion). Thanks!!
#6 by xusan on March 10, 2010 - 11:06 pm
how do you edit manifaest in my senario it reganarated file content.
#7 by david.poll on March 11, 2010 - 1:06 am
Xusan,
I’m not sure I follow what you mean here. Which manifest are you talking about (the AppManifest.xaml file? Something else?)?
-David
#8 by shane on March 13, 2010 - 5:00 pm
Do you use XapLoader and XapContentLoader on SL 3?
#9 by david.poll on March 15, 2010 - 10:33 am
XapContentLoader can’t be used with Silverlight 3 because the ContentLoader feature for Navigation is new to Silverlight 4. XapLoader uses some Silverlight 4-specific APIs, and is thus also dependent upon Silverlight 4. The good news, however, is that the Silverlight 4 RC was just announced
.
#10 by DJ on March 23, 2010 - 4:54 am
David,
Thank you for you posts, I am very new to silverlight and truely appreciate all of the information you have on line, it is very useful. I am unable to get your example working for dynamicly loading SL4 assemblys. When I add your SLab.Navigation.ContentLoader.XAP as a reference my project will not build saying that it would cause my app to be sandboxed in a previous version of the .net framework. I am currently using Win7, SL4nonRC .net4, and vs2010beta2. I am in great need of partitioning my appliction into several different XAPs and almost have it. (I can’t get the shim page to work either, but understand that is SL3) It almost works in 4… Any guidance would be a greatly appreciated. Thanks again…
#11 by DJ on March 23, 2010 - 6:24 am
David,
I have solved my own problem. I was actually able to get the shim method working and for now it will have to be my solution. I will defenitly keep an eye on the developement of this type of solution. Thanks again for all of your work.
#12 by Stephen on April 18, 2010 - 4:26 pm
Hi David,
Thanks for your blog post. I have a few questions regarding the Silverlight 4 solution to this problem.
Is there any way for the Content Loader to know that MEF (or another framework) is already in the process of downloading external content, or is this something that will need to managed through application logic? By the same token, if MEF has already downloaded an external component will the ContentLoader re-download it again, or simply use the version MEF downloaded?
One big appeal of MEF is that you don’t necessarily ‘know’ the physical locations of your files at design time. In this case would you recommend using the ContentLoader in code directly to inform it of libraries MEF downloaded?
#13 by Jeff Klawiter on April 21, 2010 - 6:33 am
Thank you so much for the XapLoader. It saved me a lot of headaches trying to implement it. It is my opinion SL needs to support this scenario out of the box. Be able to download a Xap and auto include the assemblies and resources. At least for gods sake let us get a list of the items within the Xap. The StreamResourceInfo class is a joke.. it exposes no information. Application.GetStreamResourceNames()?? ok, rant over.
I think the XapLoader component should be put up on Codeplex. I’d love to add some extensions on to it like auto add assemblies to the deployment parts.
#14 by Alexey on May 6, 2010 - 12:06 am
Hi, David. You have mentioned that in latest version of the SLab you added visibility functional based on the user roles (.NET RIA service) to the SLab navigation. What I meant? User for example not authenticated and do’t seen a navigation menu, but after successfull authentication and authorization he can see only thaath menu items which allowed his roles.
Could you provide please such example ? Thank’s.
#15 by devis maisons on May 6, 2010 - 1:25 am
Thanks you for his very useful informations.
Very good blog !
#16 by Nk54 on May 12, 2010 - 7:09 am
Hi David ! I find your solution easier thant doing a mef xap dynamic load. But i can’t make it work on silverlight 4 with your last project v0.7 and with the 0.3 project.
System.IO.FileNotFoundException
Could not load file or assembly 'SLaB.Navigation.ContentLoaders.Utilities, Version=0.7.5.0, Culture=neutral, PublicKeyToken=c1adbec159a0aa41' or one of its dependencies. Le fichier spécifié est introuvable.
Thanks !
#17 by david.poll on May 12, 2010 - 10:47 am
Make sure to reference both SLaB.Navigation.ContentLoaders.Utilities and SLaB.Navigation.ContentLoaders.Xap in your project. Your references to the 0.3 versions may be sticking around (I sometimes have this problem with VS — it continues to pick up older versions even after deleting/re-adding references).
Let me know if that helps.
#18 by Les Prigmore on May 15, 2010 - 2:17 pm
Hi David, I was having the same problem as “Nk54″ (#12). on Line 19, col 13 of ErrorPage.xaml.cs. I started out using/experimenting with your technique and libraries with ver 0.6. After a few days, I noticed that there was a ver 0.7 So I was being “clever” and thought that you must have fixed a bug or something and I substituted the ver 0.6 dlls with the ver 0.7 dlls. That is when the problem cropped up. Then I switch back to ver 0.6 dlls and every thing works again. However, ver 0.7 works fine in your ver 0.7 demo app “ScratchApplication”. I guess that stranger than this might have happened before. But this one has me stumped for now. But I do like your tehnique about getting at the navigation issues. Maybe some day we can figure out the “Could not load…” issue too. Good luck and have a great day….Les
#19 by Tom Brewer on May 12, 2010 - 9:13 am
Hi David, it’s good to see such useful stuff. I was wandering, though, as I have managed to load my own assemblies & resources from an external XAP, how I can now navigate to XAML pages within the loaded assemblies without referencing the whole SLaB thing? Do I just implement some special version of the INavigationContentLoader? I’m not sure how I’d format the URI to know to pull a page from a loaded assembly. As an example I’ve tried
/MyComponent;component/Views/MyPage.xaml
but it doesn’t seem to resolve the reference, even with the assembly loaded?
#20 by david.poll on May 12, 2010 - 10:50 am
For your example, you’d need to write a custom INavigationContentLoader and provide it with a way to access the loaded assemblies (e.g. provide a list of the assemblies as input to the content loader). The Uri you have above should work just fine, but it’ll be up to you to parse it and locate the XAML file for what you want it to do. The code for this can literally be identical to the code in the PageResourceContentLoader in the SDK (and very similar to my XapContentLoader). The only difference will be the final step of creating an instance of the class based on the x:Class attribute in XAML (you’ll need to use the reference to the assembly in order to do this).
#21 by david.poll on May 12, 2010 - 12:25 pm
The good news is, I just (literally this morning) came up with a way to do this generically enough that it should work automatically for all dynamically-loaded assemblies. I’m going to try to package it up into a simple ContentLoader that you could use (it’ll be in SLaB, but SLaB is divided into a bunch of small assembleis rather than one big one. You don’t have to take all of it in order to get the functionality).
#22 by Tom Brewer on May 17, 2010 - 3:05 am
That’d be great – thanks for responding so quickly. Is there somewhere I can see or download that from?
#23 by david.poll on May 24, 2010 - 10:18 am
Tom,
I’ve just added this in v0.8 (check out the downloads/samples page). You can simply replace the PageResourceContentLoader with the one in SLaB and the rest should just work!
The XapContentLoader also supports this now as well.
-David
#24 by Hassan on May 16, 2010 - 1:24 am
Can I create HyperlinkButton or Image at run time and assign click event to it so the click will navigate to page in external xap pz give sample code thnx for your help
#25 by Hassan on May 16, 2010 - 12:40 pm
Dear David I need to create button at run time and assign to it click event navigate to page at external xap is there sample code for this thnx for your help
#26 by Ian on June 22, 2010 - 12:37 pm
Hello Mr David Poll.
I’ve read your article about “On-demand loading of assemblies with Silverlight Navigation – Revisited for Silverlight 4 Beta.”
I have implemented a very similar approach using custom INavigationContentLoader with MEF. The problem I am having is the BusyIndicator.
When I navigate from page to page, or downloads xap dynamically, the BusyIndicator does not show up. I can see that the page is getting
disabled but the control itself is not displaying.
Here is my sample code:
MainPage.xaml:
xapService:XapViewLoader /> /navigation:Frame.ContentLoader>
XapViewLoader.cs:
public static readonly DependencyProperty IsBusyProperty = DependencyProperty.Register(“IsBusy”, typeof(bool), typeof(XapViewLoader), new PropertyMetadata(false));
public bool IsBusy
{ get { return (bool)GetValue(IsBusyProperty); }
private set { SetValue(IsBusyProperty, value); }
}
then I have some methods that load xap dynamically in this class and displays the requested page, and sets the IsBusy to true or false…
private void Load(Uri targetUri)
{
… this.IsBusy = true;
…
}
public LoadResult EndLoad(IAsyncResult asyncResult)
{
….
this.IsBusy = false;
….
}
Again, I can see that the current page gets disabled when IsBusy = true but the BusyIndicator control itself does not show up.
I am hoping that you could help me with this since your articles have been helpful to me.
Thank you,
Ian
#27 by david.poll on June 23, 2010 - 11:35 am
Ian, can you please re-post your XAML using the code tags (see the note about this below the comment box)? XML that doesn’t fall into those tags gets automatically stripped out of comments.
#28 by Ian on June 24, 2010 - 3:07 pm
I’m sorry… I don’t do really do this a lot that’s why
. Anyway, here is the xaml…
Thank you so much for taking the time to look into this.
Regards,
Ian
#29 by Ian on June 24, 2010 - 3:09 pm
#30 by Ian on June 24, 2010 - 3:10 pm
#31 by Ian on June 24, 2010 - 3:12 pm
Hi David, I did wrap with [code][/code] but still can’t see the xaml.
#32 by david.poll on July 6, 2010 - 12:46 pm
Ian,
Sorry for the delayed response — I’ve been on vacation for the last 10 days.
Can you e-mail me the XAML? david dot poll at microsoft dot com.
-David
#33 by Michael on June 25, 2010 - 12:03 pm
Hi David,
I am a VB programmer. We have an application with several hundred XAP files that need to be dynamically downloaded. We have this running now using a web client and reflection. We want to get the navigation running using SL 4. I have tried to use your libraries but I can’t get them to run and the C# is beyond me. Our code that runs now is like this:
ContentFrame.Content = TryCast(asm.CreateInstance(“PageName.Page”), UIElement)
It seems if I can just use the ContentFrame.Source property instead of the ContentFrame.Content property then it might work with navigation. I have tried to setup the uri like this:
Uri “pack://application:,,,/PageName.Page.xaml”, UriKind.Relative)
But I get an invalid port number. Before I continue on with this approach, do you think this can work?
If I can just figure out how to setup the uri for the assembly and set the ContentFrame.Source property to the uri will that load the page and do the navigation?
Thanks for taking the time to help an old VB guy.
Michael
#34 by david.poll on July 6, 2010 - 12:43 pm
Michael,
Sorry for the delayed response — I’ve been on vacation for the last 10 days.
Yes, this should indeed work. I’d be willing to bet that the issue you’re encountering is related to Uri parsing and the “pack://” protocol. As mentioned in the post (it’s easy to miss — it’s just one line
), you need to have this line of code somewhere in your app initialization:
PackUriParser.Initialize()This should help eliminate the port number issue (I hope!).
Let me know if it doesn’t!
-David
#35 by Michael on July 9, 2010 - 9:59 am
I am getting closer…
I can load your little video by pasting the uri into the address bar.
I want to load your video by clicking on a button that I added. I place the same #pack://… into a Uri in code and then assign it to the ContentFrame.Source. The address bar doesn’t erase the #Home and then it adds a $pack://… and then the rest of your video uri. How do I get a regular command button to do what pasting in the address bar is doing?
Thanks
#36 by david.poll on July 9, 2010 - 10:12 am
You don’t need the “#” sign — that indicates a fragment. Frame.Source’s value comes from everything after the “#” sign in the address bar of the browser.
#37 by Michael on July 9, 2010 - 3:44 pm
Thanks David!
I have it working now!
Michael
#38 by Jeffrey on July 21, 2010 - 8:59 pm
Excellent solution. Thank you, David!
How do I navigate in code-behind?
#39 by david.poll on August 2, 2010 - 5:56 pm
Navigating in code-behind is as easy as calling either Frame.Navigate() and passing a Uri (if you’re in a place where you have access to the Frame) or calling Page.NavigationService.Navigate() if you only have access to the current Page.
#40 by Devis on July 30, 2010 - 9:44 am
I have an error 500 when i test this solution.
Have you an idea ?
thanks
#41 by david.poll on August 2, 2010 - 5:57 pm
Can you try again and tell me the steps you took to get that error?
#42 by Hax on August 4, 2010 - 6:25 pm
Hi, David
I just find a issue, if you navigate to external page in other xap files and then refresh browser, an error will occored. Hope you can resolve it.
#43 by david.poll on August 4, 2010 - 6:53 pm
This shouldn’t be happening… I can’t get it to repro. Can you give me detailed steps?
#44 by Roy on August 5, 2010 - 2:05 am
Hi, Guy
Can navigation framework navigate to a page in the tabcontrol? just like firefox tabs
for example:
Page1====>shown in the first tabitem
Page2====>shown in the second tabitem
then user can switch diffrent page in the tabcontrol
#45 by eax on September 8, 2010 - 7:35 pm
When using MEF, I discovered that refering to the external module views (via silverlight navigation framwork) exposes the assembly/namespace on the Url address bar. The problem is that my module extensions need to have a friendly name (no namespace;component…etc).
I am hoping there is a way because right now I switched to using Prism for on-demand loading. But now i’ve reached a brick wall as apparently on-demand loaded libraries can’t have code-behind (x:class) associated with Xaml files!
Seeking advice. Thanks!
#46 by moshe sagee on December 3, 2010 - 11:27 pm
hi,
how can i pass params from main app to dynamic xaps ?
thanks
#47 by david.poll on December 6, 2010 - 2:01 am
You can do this in the same way you would with any other navigation action: query parameters. For example, you might navigate to “/Page.xaml?param1=value1¶m2=value2″, etc. You can then access these using NavigationContext.QueryString from within the loaded page.
#48 by moshe sagee on December 6, 2010 - 4:51 am
is there another way to pass params from main page to the dynamic xap except query string
(i have for ex: permission object that loaded in the main page and i want to share its with all the xaps.
#49 by Travis on December 9, 2010 - 12:45 pm
Thanks David. As a newbie to Silverlight (just in it for 3 days) this was the first thing I needed to do.
Coming from Flash development I’m used to just loading SWFs into movieclips left and right. I was surprised to find it wasn’t native to Silverlight.
I implemented it in a Tab control, just sticking nav frames in each tab item so that your loader loads a new page for each tab item.
Very nice.
#50 by Travis on December 17, 2010 - 12:57 am
Hi David. Do you know of any problems with xaploader and the iframe tag?
I struggled all day trying something and found if I removed the inline iframe tag after my object tag containing my xap, the problem went away.
I could probably show simple steps to reproduce if you’re interested.
Thanks again,
Travis
#51 by Peter on December 29, 2010 - 2:53 am
Hey David
Firstly thanks a lot for this fine work
I am working on a module based application – and this is exactly what I need
Great work…
A small thing i noticed is that in the v. 0.10 release in the ScratchContent project the AuthContentLoader in MainPage.xaml is not binding the Principal value, this caused me a bit of problems until I realised what was actually going on
I needed to check if a user had a certain role and the Principal value was alwas null.
After adding this Principal=”{Binding User, Source={StaticResource WebContext}}” to the AuthContentLoader everything was working thought – including roles
Thanks a bunch!
Best regards
Peter
#52 by Diego on January 4, 2011 - 5:04 am
Hi David, I’m having a problem when using MEF ContentLoader. I’m using it inside a RadWindow from Telerik, each time the user opens a page, I open a new window. But all of them are opening the same page. When I debug, the BeginLoad method always gets the first page opened. Do you have any ideas why this is happening? Tks.
#53 by Mark on January 12, 2011 - 10:21 am
Hi,
I have your solution working for a XAP file with standard controls in it but as soon as I try to use third party components it blows up saying:
Code: 4004
Category: ManagedRuntimeError
Message: System.Exception: A failure in loading a xap occurred System.ArgumentNullException: Value cannot be null.
I am new to Silverlight but I am guessing that some required third party files are not being brought down. Can you tell me what I am missing?
I wish this mechanism was built into Silverlight as standard as it seems pretty obvious that this is how most epople will want ot architect their applications!
Regards,
Mark
#54 by david.poll on January 12, 2011 - 12:25 pm
Strange — I don’t know what’s causing this. Can you look at the inner exception to see what the full details are?
#55 by Mark on January 12, 2011 - 12:38 pm
I will try although I don’t seem to be able to debug or anything. It happens when the external XAP file uses components from Intersoft or from ComponentArt. I have not tried any other components. I will see if I can get more error info and let you know.
#56 by Waleed on January 23, 2011 - 5:29 am
Dear David,
I refresh this page and I found my posts are back-dated to the year 1999, why is that …
#57 by Peter on March 4, 2011 - 5:45 am
Hi David
I might be misusing the framework, but I have a situation where I want all (or most) of my modules to have their seperate .web project.
I was adding the .web project from each module to the main project which I just today figured out caused the autogenerated code to be available in both the Module.dll and Main.dll which caused some conflicts (im using wcf ria services – hence the code generation). My question is – how do I properly add modules with their own .web project.
Sorry for the somewhat messy explanation
Best regards and hope you can help… Because I have loved your SLaB so far
/Peter
#58 by Peter on March 7, 2011 - 12:46 am
Nevermind – my bad, the structure of one project was faulty!
#59 by isheeple on April 6, 2011 - 8:43 am
David, nice work. Looking through the code I do not see a way to monitor when downloading is complete – did I miss it or do I need to add that myself?
#60 by isheeple on April 6, 2011 - 8:46 am
Sorry I submitted too soon. I have a case where I need to tell something else to recompose when I am done downloading the request xap + lazy assemblies and I was looking for a hook.
#61 by Kyre on May 1, 2011 - 4:51 pm
Hello!.
(First of all, excuse my english, is not my first language)
Very interesting job, thanks.
I have read the article, it’s very interesting. I donwloaded and ran the examples, and now I have a question.
When we execute an app and we access to diferents xamls in the same xap, only donwload this xap once. (Ok, that’s expected) But if we run de app few days after and navigate to one of those xamls, the app checks if it must download de xap again or will use the xap downloaded few days ago?
In other words: EVERY time I navigate to a xaml (in independent executions in the same pc) app will download xap?
Thanks again.
#62 by david.poll on May 4, 2011 - 10:05 am
By default, Silverlight will cache these downloads. More importantly, however, the CLR in Silverlight will only load an assembly once — subsequent attempts to load an assembly with the same name (even if it’s not identical) will continue to reuse the original assembly loaded. With a ContentLoader, however, you could specify a different scheme that uses assemblies with different names each time the URL is requested, and this would help get you around this problem.
#63 by Peter on June 10, 2011 - 6:11 am
Hi David
I seem to be struggeling a bit with implementing a solution for the “cache loading problem”. I would very much like to reload xap’s that has been modified (a little like what is done with a HttpHandler on this page – http://stackoverflow.com/questions/2281919/expiry-silverlight-xap-file-from-browser-cache-programmatically/4997375#4997375) however I am afraid that I cannot get it to work – not even with inspiration from your XapContentLoader.
Would you consider implementing something that can help with the loading of modified assemblies/xaps. Maybe some kind of versioning. If you do not have the time, do you perhaps have some hints as to how to get it implemented?
Any help would be much appriciated…
Best Regards
Peter
#64 by david.poll on June 10, 2011 - 8:43 am
Peter,
It’s a bit difficult — Silverlight doesn’t support what you need to do this: multiple AppDomains. This is how you would accomplish this kind of version isolation that you’re describing. The only thing I can think of is to regenerate the assemblies before they’re loaded, changing the names of all of the classes (and updating references within). You might be able to do this with Reflection emit or some other tools along those lines, but it’s likely to be slow and bug-prone (e.g. if you change the name of a class and the class is referenced in XAML, you’d better understand how to change the XAML to get the right result).
-David
#65 by Alexander on June 6, 2011 - 3:32 am
Hi David.
Can you please share the Source of Sample, cant find and download it!
Thanks.
#66 by Peter on June 11, 2011 - 2:42 pm
Hi David
After weighing the pros and cons, I decided to go with storing the xaps in the isolated storage – using it as a cache. I think this gives me more control and allows me to create some sort of versioning as well. Though obviously there are some drawbacks as well…
It could be done with minimal modification to your SLaB code, and a custom ContentLoader…
Thanks
/Peter
#67 by Hyacinth Broadchest on July 18, 2011 - 12:59 am
Hi David,
Worked brilliantly in my Sliverlight Navigation project. Then I tried to apply that to a SL Business Applications WCF RIA project, and can’t really get it to work at all. Symptoms are: It packages all the SLaB dlls into the xap. And attempting to load one of those new xaps throws an error. xaps generated under the SL Nav project and copied into /ClientBin still work fine, but these can’t access the data services…
Many thanks, Hyacinth.
#68 by brennt on July 29, 2011 - 3:28 am
hi, im not using your code, but…
when im trying to go like this:
InternalContentFrame.Navigate(new Uri("P1.xaml", UriKind.RelativeOrAbsolute));[code]i get an exception:
The type "AssemblyName.Views.P1" specified in the x:Class of "AssemblyName;component/Views/P1.xaml" could not be found in any loaded assembly.
which cant be true coz
1. control containing FRAME is located in the same assembly
2. this works like a charm:
[code]
[ImportMany(AllowRecomposition = true)]
public Page[] MEFPagesList { get; set; }
private void ContentFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
{
e.Handled = true;
InternalContentFrame.Content = MEFPagesList[0];
}
unfortunately it does not support any of the "navigation" properties e.g. browser navigation support
can anyone help?