Getting Started with Adobe After Effects - Part 6: Motion Blur
First Time? You can support us by signing up. It takes only 5 seconds. Click here to sign up. If you already have an account, click here to login.
Loading

1st Prize - Apple iPad


DOTNET Quiz 2011 - Silverlight Question: Resources usage

  • My application partitioned into two XAP packages: First (main) XAP file, fairly small to allow fast loading. It has all application libraries (DLLs), but has no resources. Second XAP file has DLL with embedded resources and some Content resources.

    Question: how to use the resources from second XAP file in first (main) XAP file?

    Posted on 01-15-2011 00:00 |
    AlexGolesh
    1008 · 0% · 25

4  Answers  

Subscribe to Notifications
  • Score
    1

    The Managed Extensibility Framework can be used for this purpose which is now part of .NET4 and sliverlight 4.

    Replied on Jan 15 2011 4:52AM  . 
    Pradeep Kumar
    299 · 0% · 145
  • Score
    6

    For additional DLLs to work with a small initial XAP file, you have to put the DLLs into the ClientBin folder of your app. Then, inside your code, you can load the DLLs at any time you need them using the WebClient class.

    private void LoadExtensionDll()
    {
        WebClient client = new WebClient();
        client.DownloadDataCompleted +=new DownloadDataCompletedEventHandler(OnDownloadDataCompleted);
        client.DownloadData(myExtensionUri);
    }
    
    private void OnDownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
    {
        AssemblyPart part = new AssemblyPart();
        Assembly myLib = part.Load(e.Result);
    }
    

    Unfortunately, you can access objects from this loaded library only with Activator.CreateInstance(), as strong typing is (normally) not possible with lazy loaded code.

    Replied on Jan 23 2011 12:41PM  . 
    Guenter
    28 · 6% · 1822
  • Score
    8

    Tips before you use 1. If you add a DeploymentCatalog without passing any Uri, it will, by default, parse the contents of the current active XAP, so that is always a "default" catalog to add to the aggregate one to grab the current parts

    1. When you have other XAP files, it is extremely important to set duplicate assembly references to copy-local=false. When you duplicate assemblies in the XAPs it can create issues with them being loaded multiple times into the app domain.

    2. The main purpose of MEF is related to parts which are contracts, imports, and exports. Therefore, MEF's functionality depends on types. If you were to create a file that only contained styles or other assets, for example, there is nothing for MEF to do because it's not designed to manage those types of resources. Those are best referenced and loaded in one of the other assemblies that do have functionality.

    Need to add MEF References

    System.ComponentModel.Composition.dll , System.ComponentModel.Composition.Initialization.dll. System.ComponentModel.Composition.dll. System.ComponentModel.Composition.dll.

    Add new interface to contract

        public interface IDeploymentCatalogService
    
        {
    
            void AddXap(string uri, Action<AsyncCompletedEventArgs> completedAction = null);
    
            void RemoveXap(string uri);
    
                }
    
    Add new deployment contract service to project
    
    Export(typeof(IDeploymentCatalogService))]
    
    public class DeploymentCatalogService : IDeploymentCatalogService
    
    {
    
        private static AggregateCatalog _aggregateCatalog;
    
    
        Dictionary<string, DeploymentCatalog> _catalogs;
    
    
        public DeploymentCatalogService()
    
        {
    
            _catalogs = new Dictionary<string, DeploymentCatalog>();
    
        }
    
    
        public static void Initialize()
    
        {
    
            _aggregateCatalog = new AggregateCatalog();
    
            _aggregateCatalog.Catalogs.Add(new DeploymentCatalog());
    
            CompositionHost.Initialize(_aggregateCatalog);
    
        }
    
    
        public void AddXap(string uri, Action<AsyncCompletedEventArgs> completedAction = null )
    
        {
    
            DeploymentCatalog catalog;
    
            if (!_catalogs.TryGetValue(uri, out catalog))
    
            {
    
                catalog = new DeploymentCatalog(uri);
    
                if (completedAction != null)
    
                    catalog.DownloadCompleted += (s, e) => completedAction(e);
    
                else
    
                    catalog.DownloadCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(catalog_DownloadCompleted);
    
    
                catalog.DownloadAsync();
    
                _catalogs[uri] = catalog;
    
            }
    
            _aggregateCatalog.Catalogs.Add(catalog);
    
        }
    
    
        void catalog_DownloadCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
    
        {
    
            if (e.Error != null)
    
                throw e.Error;
    
        }
    
    
        public void RemoveXap(string uri)
    
        {
    
            DeploymentCatalog catalog;
    
            if (_catalogs.TryGetValue(uri, out catalog))
    
            {
    
                _aggregateCatalog.Catalogs.Remove(catalog);
    
            }
    
        }
    
    }
    

    DeploymentCatalogService handles adding / removal of DeploymentCatalogs. It also exposes a static Initialize method which handles setting up the host to allow dynamic download. This method creates an aggregate catalog, and adds the parts in the default XAP to it. It then calls CompositionHost.Initialize to pass that catalog to the host. Once the host has been configured, any catalogs added to the aggregate will then automatically show up in the host.

    Note: DeploymentCatalogService is simply a helper, it is NOT required in order to use DeploymentCatalog.

    Intialize tho host in application_startup Now that DeploymentCatalogService is added, go remove the old Initialization code which used PackageCatalog from the App class and have it call Initialize.

    private void Application_Startup(object sender, StartupEventArgs e)
    
    {
    
        DeploymentCatalogService.Initialize();
    
        this.RootVisual = new MainPage();
    
    }
    

    Refactor the widget

    ExportWidget(Location=WidgetLocation.Top)]

    public partial class Widget1 : UserControl

    {

    [Import]
    
    public IDeploymentCatalogService CatalogService { get; set; }
    
    
    public Widget1()
    
    {
    
        InitializeComponent();
    
        Button.Click += new RoutedEventHandler(Button_Click);
    
    }
    
    
    void Button_Click(object sender, RoutedEventArgs e)
    
    {
    
        CatalogService.AddXap("HelloMEF.Extensions.xap");
    
    }
    

    }

    Build now , now we can see the XAP is dynamically loaded from anothere XAP

    Replied on Feb 17 2011 2:31AM  . 
    Vamshi
    131 · 1% · 376
  • Score
    9

    To dynamically load the second XAP file we have to deploy it along with the library assemblies into or around your ClientBin folder (in this case you'll be able to use relative path otherwise you'll have to specify an absolute path). Then we can use WebClient to download them on demand. So, here is a small simplified example on how to do it:

    // This code should be placed where you want to download the dll
    
    WebClient client = new WebClient(); 
    client.OpenReadCompleted += OpenReadCompletedEventHandler(OnOpenReadCompleted); 
    client.OpenReadAsync(new Uri("ResourcesAndContent.xap", UriKind.Relative));
    

    And OpenReadCompleted event handler :

    void OnOpenReadCompleted(object sender, OpenReadCompletedEventArgs e) 
    { 
    StreamResourceInfo sri = new StreamResourceInfo(e.Result, null); 
    StreamResourceInfo resourcesDll = Application.GetResourceStream(sri, new Uri("Resources.dll", UriKind.Relative)); 
    AssemblyPart assmPart = new AssemblyPart(); 
    Assembly assm = assmPart.Load(resourcesDll.Stream); 
    ...
    }
    

    As you can see it's possible to load assemblies one by one, whenever required. There is a nice article by Eric Mork Dynamically Loading .Dlls in Silverlight and small sample of A Smaller XAP Preloader for Silverlight that provide more details on the method for dynamic loading of XAP file described above.There are also other ways to load libraries dynamically, e.g. using DeploymentCatalog in Managed Extensibility Framework (MEF). You can find explanation and a sample here Managed Extensibility Framework Overview .

    Even more interesting things come into play when you have to use objects from a loaded assembly. The easiest (but not the most convenient and type safe) way is to use reflection to work with objects and types from a loaded library. So, couple samples on how it will look:

    MyControl mc = (MyControl)assm.CreateInstance("Whatever.MyControl"); // Create an object
    
    Type t = assm.GetType("Resources.Class1"); // Get type
    string s = (string)t.InvokeMember("getData", BindingFlags.InvokeMethod, null, null, null); // Call static method
    

    Using reflections has its downsides though. It's not as clear as regular coding and you loose benefits of strong typing that you have in regular C# or VB code. Good news that there is a way to use dynamic loading but still have benefits of strong typing and write code in a more readable format. There is a nice post from Jeff Prosise Cool Silverlight Trick #3 that explains in really deep details how to do so. Just to bring a general idea I will quote some of his main steps here:

    1 . Add a reference to the library assembly to your Silverlight project, but change the “Copy Local” setting in the reference’s properties from true to false. This prevents Visual Studio from embedding the library assembly in the XAP file, but since the project contains a valid reference to the assembly, the compiler knows all about the types in it and will allow you to use them—even new them up.

    2 . At run-time, use WebClient to download the assembly and AssemblyPart.Load to load it.

    3 . Here’s the critical part. After loading the assembly, call a separate method to instantiate one of the assembly’s types, and decorate that method with a MethodImpl(MethodImplOptions.NoInlining) attribute. In addition, do not reference any of the types inside the library assembly in the method that loads the assembly. If you do, you’ll shoot yourself in the foot and what you’re trying to do will not work. Period.

    So, using dynamically loading library is a really nice feature that helps to improve user experience with little extra work required.

    Replied on Mar 15 2011 12:31AM  . 
    Dmitry Kharlap (aka Docker)
    148 · 1% · 325

Your Answer


Sign Up or Login to post an answer.
Please note that your answer will not be considered as part of the contest because the competition is over. You can still post an answer to share your knowledge with the community.

Copyright © Rivera Informatic Private Ltd.