Tips, Tricks, and Techniques for Building Killer Silverlight Apps Jeff Prosise
Dynamic Assembly Loading AssemblyPart class represents an assembly that's part of a Silverlight application Assemblies typically packaged in XAPs AssemblyPart.Load loads assemblies into appdomains at run- time The key to dynamic assembly loading, but… Beware the JIT compiler! 2
Loading an Assembly 3 WebClient wc = new WebClient(); wc.OpenReadCompleted += OnOpenReadCompleted; wc.OpenReadAsync(new Uri("Widget.dll", UriKind.Relative));. private void OnOpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { if (e.Error == null) { AssemblyPart part = new AssemblyPart(); part.Load(e.Result); }
DEMO Dynamic Assembly Loading
Dynamic XAP Loading XAPs can be loaded dynamically, too Download with WebClient Extract AppManifest.xaml from XAP and enumerate assemblies ("parts") Extract assemblies and load with AssemblyPart.Load Create class-library XAP by starting with Silverlight Application, not Silverlight Class Library
Enumerating Assemblies in a XAP 6 StreamResourceInfo sri = new StreamResourceInfo(xap, null); XmlReader reader = XmlReader.Create (Application.GetResourceStream(sri, new Uri("AppManifest.xaml", UriKind.Relative)).Stream); AssemblyPartCollection parts = new AssemblyPartCollection(); if (reader.Read()) { reader.ReadStartElement(); if (reader.ReadToNextSibling("Deployment.Parts")) { while (reader.ReadToFollowing("AssemblyPart")) { parts.Add(new AssemblyPart() { Source = reader.GetAttribute("Source") }); }
Loading Enumerated Assemblies 7 foreach (AssemblyPart part in parts) { Stream assembly = Application.GetResourceStream (sri, new Uri(part.Source, UriKind.Relative)).Stream; part.Load(assembly); }
DEMO Dynamic XAP Loading
Dynamic Localization Silverlight supports RESX localization Create resource DLLs from RESX files Resource DLLs == Satellite assemblies Data-bind XAML elements to auto-generated ResourceManager wrapper Two challenges How do you switch languages at run-time? How do you download satellite assemblies on demand rather than embed them in the XAP?
ObservableResources 10 public class ObservableResources : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private static T _resources; public T LocalizationResources { get { return _resources; } } public ObservableResources(T resources) { _resources = resources; } public void UpdateBindings() { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("LocalizationResources")); }
Enumerating Satellite Assemblies 11 StreamResourceInfo sri = new StreamResourceInfo(xap, null); XmlReader reader = XmlReader.Create (Application.GetResourceStream(sri, new Uri("AppManifest.xaml", UriKind.Relative)).Stream); AssemblyPartCollection parts = new AssemblyPartCollection(); if (reader.Read()) { reader.ReadStartElement(); if (reader.ReadToNextSibling("Deployment.Parts")) { while (reader.ReadToFollowing("AssemblyPart")) { parts.Add(new AssemblyPart() { Source = reader.GetAttribute("Source") }); }
Loading Satellite Assemblies 12 foreach (AssemblyPart part in parts) { if (part.Source.ToLower().Contains("resources.dll")) { Stream assembly = Application.GetResourceStream (sri, new Uri(part.Source, UriKind.Relative)).Stream; part.Load(assembly); }
DEMO Dynamic Localization
Dynamic Page Loading Navigation framework provides infrastructure for multi-page apps Default content loader loads pages from XAP PageResourceContentLoader No built-in support for remote XAPs Custom content loaders can load them from anywhere -INavigationContentLoader
Do-Nothing Content Loader 15 public class CustomContentLoader : INavigationContentLoader { private PageResourceContentLoader _loader = new PageResourceContentLoader(); public IAsyncResult BeginLoad(Uri targetUri, Uri currentUri, AsyncCallback userCallback, object asyncState) { return _loader.BeginLoad(targetUri, currentUri, userCallback, asyncState); } public bool CanLoad(Uri targetUri, Uri currentUri) { return _loader.CanLoad(AddFileNameExtension(targetUri), currentUri); } public void CancelLoad(IAsyncResult asyncResult) { _loader.CancelLoad(asyncResult); } public LoadResult EndLoad(IAsyncResult asyncResult) { return _loader.EndLoad(asyncResult); }
Registering a Content Loader 16
DEMO Dynamic Page Loading
Behaviors Combine triggers and actions into one package Useful when user-input events and actions taken in response to those events are tightly bound e.g., drag behavior requires coupling of MouseLeftButtonDown, MouseMove, and MouseLeftButtonUp events Derive from Behavior or Behavior Override OnAttached and OnDetaching AssociatedObject property references attachee 18
Implementing a Behavior 19 public class DisappearBehavior : Behavior { protected override void OnAttached() { base.OnAttached(); AssociatedObject.MouseLeftButtonDown += OnClick; } protected override void OnDetaching() { base.OnDetaching(); AssociatedObject.MouseLeftButtonDown -= OnClick; } private void OnClick(object sender, MouseButtonEventArgs e) { AssociatedObject.Visibility = Visibility.Collapsed; }
Applying a Behavior 20 xmlns:local="clr-namespace:namespace" xmlns:i="clr-namespace:System.Windows.Interactivity; assembly=System.Windows.Interactivity".
DEMO Behaviors
Stay up to date with MSDN Belux Register for our newsletters and stay up to date: Technical updates Event announcements and registration Top downloads Follow our blog Join us on Facebook LinkedIn: Download MSDN/TechNet Desktop Gadget
TechDays 2011 On-Demand Watch this session on-demand via Channel9 Download to your favorite MP3 or video player Get access to slides and recommended resources by the speakers
THANK YOU