Tune Up Your PC

Tune up your PC with our tools and information today!

  • Home
  • About

31

Jul

Silverlight 3 Navigation: Dynamically Loaded Pages… Now MEF Powered!

Posted by admin  Published in windows, xp

Recently David Poll posted a very cool technique for navigating to dynamically loaded pages and on demand downloading of pages in a Silverlight 3 application .  It was very cool but the explicit wire up of each page can be a pain in large applications.  So having just posted about MEF on Silverlight, I thought this was a great fit.  The Managed Extensibility Framework (MEF) is all about discovering and wiring up components and Silverlight 3 Navigation has some very interesting components.    But before I could get it done, our Test Manager, Dinesh Chandnani beat me to it.  He wrote this very cool example app that I extended just a bit.

Download the all the source code and check out an live sample…

The model is very simple.  You just create a page (via the Silverlight Page item template) and put metadata on them saying how to navigate to it.  The page can be in the same XAP or different XAP.  No need to wire them up.   

For example, for a page in the same XAP, you just create a page and add some metadata to it

   1: [PageMetadata(Content = "page1", NavigateUri = "/page1")]

   2: public partial class Page1 : Page

   3: {

For a page in a different assembly, possibly delay loaded or conditionally loaded:

   1: [PageMetadata(Content="delayloaded",

   2:     NavigateUri="/DelayLoadedPages;component/DelayLoadedPage.dyn.xaml")]

   3: public partial class DelayLoadedPage : DynamicPage

   4: {

Pretty much the same, but we use the packURI syntax and David Poll’s Dynamic page class\pattern (see his blog post above for more information).

If you want to load pages from an external assembly, you do need to explicitly load that assembly.  But this is pretty easy to do and it can be done at any point in the application.  When the user logs in as in an admin role, when advanced functionality is required, after initial startup of the application, etc.  The page simply appears in the nav bar when it is downloaded and running.   For example, I extended Dinesh’s code by adding an assembly that was loaded when a button is clicked.  The code is simple:

   1: private void Button_Click(object sender, RoutedEventArgs e)

   2: {

   3:     Package.DownloadPackageAsync(new Uri("DelayLoadedPages.xap", 

   4:         UriKind.Relative), DownloadCompleted);

   5:  

   6: }

   7: private void DownloadCompleted(AsyncCompletedEventArgs e, Package p)

   8: {

   9:     var app = App.Current as SilverlightMEFNavigation.App;

  10:  

  11:     if (!e.Cancelled && e.Error == null)

  12:         app.PackageCatalog.AddPackage(p);

  13: }

When the button is clicked, we download kick off an async download of the XAP (line 3-4).  Then when it is downloaded it we add it to the catalog the nav bar is tied to in line 12. 

 

Now, how does all this work?  There are afew parts really. 

First we define the PageMetadataAttribute in the main assembly.  All the pages will have to reference this, so you might want to factor it out into its own assembly..

   1: [MetadataAttribute]

   2: [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]

   3: public class PageMetadataAttribute  : ExportAttribute

   4: {

   5:     public PageMetadataAttribute() : base(typeof(FrameworkElement)) { }

   6:     public string NavigateUri { get; set; }

   7:     public string Content { get; set; }

   8:     

   9: }

A few notes:

Line 1: We set this up as a MEF Metadata attribute.. this enables the MEF engine to get composition information from this attribute

Line 2: We set this up such that it can be applied only once per type.  MEF uses this as a hit on how to compose it.

Line 3: we derive from ExportAttribute, this enables us to completely hide the MEFness out of the picture…  folks writting pages don’t need to know MEF is under the covers at all. 
Line 4: Say that this attribute will be used on FrameworkElements, a hit to MEF on how to type things. 
Lines 6-7: just set up the attribute interface we want.

 

In MainPage.cs, we have some code that populates the nav bar as new pages are discovered. 

   1: [Export]

   2: public partial class MainPage : UserControl, IPartImportsSatisfiedNotification

   3: {

   4:     [ImportMany(AllowRecomposition = true)]

   5:     public ObservableCollection<Lazy<FrameworkElement, IPageMetadata>> Pages = null;

We have a Pages collection that we have marked with AllowRecomposition, which means its value’s can change over the life of the application (such as when a new package is added as I showed above).

Then we simply update the links whenever new items are available in the Page collection.

   1: private void UpdateLinks()

   2: {

   3:     if (Pages == null || Pages.Count <= 0)

   4:         return;

   5:  

   6:     for (int i = 0; i < Pages.Count; i++)

   7:     {

   8:         if (LinksStackPanel.Children.Where(u=>(u is HyperlinkButton) 

   9:             && (u as HyperlinkButton).Content.ToString() 

  10:                     == Pages[i].Metadata.Content).FirstOrDefault() != null)

  11:             continue;

  12:         HyperlinkButton hb = new HyperlinkButton();

  13:         hb.Style = ((App)Application.Current).Resources["LinkStyle"] as Style;

  14:         hb.Content = Pages[i].Metadata.Content;

  15:         hb.NavigateUri = new Uri(Pages[i].Metadata.NavigateUri, UriKind.Relative);

  16:         LinksStackPanel.Children.Add(hb);

  17:     }

  18: }

Notice in line 12-16 we are dynamically creating the Xaml elements to add into the tree. 

The final bit of code we added was in App.cs to set MEF..

   1: private void Application_Startup(object sender, StartupEventArgs se)

   2: {

   3:     AggregateCatalog aggregateCatalog = new AggregateCatalog();

   4:     AssemblyCatalog ac = new AssemblyCatalog(Assembly.GetExecutingAssembly());

   5:     aggregateCatalog.Catalogs.Add(ac);

   6:     aggregateCatalog.Catalogs.Add(PackageCatalog);

   7:     // Load any package dynamically

   8:     Package.DownloadPackageAsync(new Uri("AdditionalPages.xap", UriKind.Relative), DownloadCompleted);

   9:     CompositionContainer container = new CompositionContainer(aggregateCatalog);

  10:     this.RootVisual = container.GetExportedValueOrDefault<MainPage>();

  11: }

Here we setup the catalog to enable MEF to look for pages in the current assembly and in an assembly we download dynamically after the app is up and running. Line 8 sets up the call to the handler below when the page has been downloaded…

   1: private void DownloadCompleted(AsyncCompletedEventArgs e, Package p)

   2: {

   3:     Thread.Sleep(1000);

   4:     if (!e.Cancelled && e.Error == null)

   5:         PackageCatalog.AddPackage(p);

   6: }

For such as simple example on my dev machine the page downloads immediately so you can’t really tell.. so I added a brief delay so you can see it pop it easier.   So the Thread.Sleep() in line 3 is there to demo better…  I highly recommend removing it in production code.

 

That is all there is to it!  A very simple solution. 

 

For more information see:

  • Eric Mok’s excellent video walk through of MEF 
  • My MEF on Silverlight Post
  • David’s Silverlight Navigation dynamic loading post

Related Articles

  • I knew where Nepal was before Raiders of the Lost Ark. Did you? (September 3rd, 2010)
  • Steve Marx Reads The Azure Tea Leaves on Connected Show #36 (September 3rd, 2010)
  • Не место красит разработчика, а… (September 3rd, 2010)
  • Quote of the Day: On the Efficiency of Government (September 3rd, 2010)
  • What happens to a named object when all handles to it are closed? (September 3rd, 2010)

No user responded in this post

Subscribe to this post comment rss or trackback url

September 2010
M T W T F S S
« Aug    
 12345
6789101112
13141516171819
20212223242526
27282930  

Blogroll

  • Development Blog
  • Documentation
  • Plugins
  • Suggest Ideas
  • Support Forum
  • Themes
  • WordPress Planet

Categories

  • computers (59)
  • email (3)
  • hardware (17)
  • Operating Systems (1)
  • security (27)
  • software (87)
  • spam (2)
  • technology (93)
  • windows (12402)
  • wireless (3)
  • xp (12397)

Archives

  • September 2010 (75)
  • August 2010 (741)
  • July 2010 (904)
  • June 2010 (594)
  • May 2010 (776)
  • April 2010 (881)
  • March 2010 (728)
  • February 2010 (794)
  • January 2010 (645)
  • December 2009 (710)
  • November 2009 (625)
  • October 2009 (653)
  • September 2009 (622)
  • August 2009 (629)
  • July 2009 (627)
  • June 2009 (652)
  • May 2009 (607)
  • April 2009 (629)
  • March 2009 (465)
  • February 2009 (40)
  • November 2008 (157)
  • October 2008 (140)

Recent Entries

  • I knew where Nepal was before Raiders of the Lost Ark. Did you?
  • What happens to a named object when all handles to it are closed?
  • Quote of the Day: On the Efficiency of Government
  • Не место красит разработчика, а…
  • Steve Marx Reads The Azure Tea Leaves on Connected Show #36
  • This is a really cool panoramic stitching tool!
  • Microsoft Dynamics ERP Licensing Guide
  • Fortnightly MSDN Flash poll
  • Analyzing Database Roundtrips with SQL Server Profiler
  • Windows Identity Foundation Samples–HTTP Watch Is Your Friend

Recent Comments

  • No Comments
  • Random Selection of Posts

    • Cumulative Update Package 5 for SQL Server 2008 Service Pack 1
    • Making The Most Out Of Your iPhone 3G Unlocking Methods
    • How to change Date Format after installing SQL server
    • Azure Access Control Service Client Patterns Part 1
    • DLL- und OCX Dateien manuell unter Windows 7 registrieren
    • Overview of Gemini features
    • FAQ: Why am i not seeing the new extension package that I added for supporting a new technology?
© 2008 Tune Up Your PC is proudly powered by WordPress
Theme designed by Roam2Rome