240 likes | 331 Views
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
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