240 likes | 334 Vues
Discover tips and techniques for dynamic assembly loading and localization in Silverlight applications. Learn how to load XAPs dynamically, enumerate assemblies, and switch languages at runtime. Explore strategies for handling satellite assemblies and custom content loaders for dynamic page loading behaviors.
E N D
Tips, Tricks, and Techniques for Building Killer Silverlight Apps Jeff Prosise http://www.wintellect.com/CS/blogs/jprosise/default.aspx http://twitter.com/#!/jprosise
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!
Loading an Assembly WebClientwc = new WebClient(); wc.OpenReadCompleted += OnOpenReadCompleted; wc.OpenReadAsync(new Uri("Widget.dll", UriKind.Relative)); . . . private void OnOpenReadCompleted(object sender, OpenReadCompletedEventArgse) { if (e.Error == null) { AssemblyPart part = new AssemblyPart(); part.Load(e.Result); } }
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 StreamResourceInfosri = 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 foreach (AssemblyPart part in parts) { Stream assembly = Application.GetResourceStream (sri, new Uri(part.Source, UriKind.Relative)).Stream; part.Load(assembly); }
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 public class ObservableResources<T> : INotifyPropertyChanged { public event PropertyChangedEventHandlerPropertyChanged; 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 StreamResourceInfosri = 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 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); } }
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 public class CustomContentLoader : INavigationContentLoader { private PageResourceContentLoader _loader = new PageResourceContentLoader(); public IAsyncResultBeginLoad(Uri targetUri, Uri currentUri, AsyncCallbackuserCallback, object asyncState) { return _loader.BeginLoad(targetUri, currentUri, userCallback, asyncState); } public boolCanLoad(Uri targetUri, Uri currentUri) { return _loader.CanLoad(AddFileNameExtension(targetUri), currentUri); } public void CancelLoad(IAsyncResultasyncResult) { _loader.CancelLoad(asyncResult); } public LoadResultEndLoad(IAsyncResultasyncResult) { return _loader.EndLoad(asyncResult); } }
Registering a Content Loader <nav:Frame x:Name="Main" Source="Home"> <nav:Frame.ContentLoader> <local:CustomContentLoader /> </nav:Frame.ContentLoader> </nav:Frame>
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<T> • Override OnAttached and OnDetaching • AssociatedObject property references attachee
Implementing a Behavior public class DisappearBehavior : Behavior<UIElement> { 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 xmlns:local="clr-namespace:namespace" xmlns:i="clr-namespace:System.Windows.Interactivity; assembly=System.Windows.Interactivity" . . . <Rectangle Width="300" Height="200" Fill="Red"> <i:Interaction.Behaviors> <local:DisappearBehavior /> </i:Interaction.Behaviors> </Rectangle>
Stay up to date with MSDN Belux • Register for our newsletters and stay up to date:http://www.msdn-newsletters.be • Technical updates • Event announcements and registration • Top downloads • Follow our bloghttp://blogs.msdn.com/belux • Join us on Facebookhttp://www.facebook.com/msdnbehttp://www.facebook.com/msdnbelux • LinkedIn: http://linkd.in/msdnbelux/ • Twitter: @msdnbelux DownloadMSDN/TechNet Desktop Gadgethttp://bit.ly/msdntngadget
TechDays 2011 On-Demand • Watchthis session on-demand via Channel9http://channel9.msdn.com/belux • Download to your favorite MP3 or video player • Get access to slides and recommended resources by the speakers