Introduction
(Note: This article is not strictly speaking for WPF only, the technique described works for any type of .NET application. In next articles, we'll study WPF-specific techniques, for example loading XAML resource assemblies dynamically.)
There are many scenarios where an application doesn't know at build time exactly which DLLs are going to be available at runtime. For example, you may want to provide a UI framework and then develop components at a later time running in that framework.
In .NET (WinForms or WPF), this is made possible by the following features:
-
UserControls (or CustomControls) derive from a well known UI component (Control), which can be loaded in a panel.
-
Assemblies can be loaded dynamically in the current AppDomain, using the methods Assembly.Load, Assembly.LoadFile, Assembly.LoadFrom.
Note: there are differences between LoadFile and LoadFrom. See
here for details.
LoadFrom must be used with care, because the assembly's identity check is less strict than when the assembly is linked at build time, or when it is loaded using LoadFile. However, for scenarios where the loaded assembly references other assemblies, LoadFile doesn't work. Also, Assembly.LoadFrom can be used to load assemblies over HTTP, which is useful for applications running as web clients (either embedded in IE like WPF XBAPs, or for web-enabled rich internet applications.)
Also, this quote from
MSDN:
"Use the LoadFile method to load and examine assemblies that have the same identity, but are located in different paths. LoadFile does not load files into the LoadFrom context, and does not resolve dependencies using the load path, as the LoadFrom method does. LoadFile is useful in this limited scenario because LoadFrom cannot be used to load assemblies that have the same identities but different paths; it will load only the first such assembly."
Design
To allow the "UI framework" to load and use the user controls located in the dynamically loaded assembly, an interface must be defined. To allow greater flexibility, this interface is defined in a separate assembly called Interfaces.dll. The user controls must implement this interface.
Additionally, the user controls may throw events, which can be caught by the containing UI framework. These events must also be defined in the interface, so that the contract is clear between both parties.
So we have the following design:
To load the plug-in assembly in the framework, we can use the following code:
// assemblyPath is "c:\\..." or "http://..."
Assembly plugInAssembly
= Assembly.LoadFrom( assemblyPath );
IComponent plugIn
= plugInAssembly.CreateInstance( "GalaSoftLb.Wpf.PlugIn.MyComponent" )
as IComponent;
plugIn.ValueChanged
+= new ValueChangedHandler( plugIn_ValueChanged );
this.Content = plugIn;
After we load the plug-in assembly, we instantiate the plug-in, subscribe to its event and then (in WPF), we assign the newly created plug-in to be the window's content. This is possible without casting, because the Content property is of type object. Of course, if the plug-in is not of a suitable type, an exception will be thrown at runtime.
Because LoadFrom is very versatile, you can use it to load files located on the file system (you'll need FileIOPermission) or files located on the web (you'll need WebPermission). Note however that you can only load DLLs located on the XBAP's server-of-origin).
In WPF, we have one more very important reason to want to load assemblies dynamically: Styles! With WPF, a new workflow between software developers and graphics designers is made possible by the separation of content and design information. The developer concentrates on the application's functionality, and the designer on the look&feel. To allow a smooth workflow, it makes sense to store the resources which the designers will work on in separate assemblies. These assemblies will typically be compiled at a later time. Also, we may have various themes, so various assemblies with different versions of the same resources. This is what we will concentrate on in the next article (coming soon ;-)
Print | posted on Wednesday, March 07, 2007 6:31 PM