Site Logo

Pixel-in-Gene

Exploring Frontend Development with Design / Graphics / Technology

Application.LoadComponent() from un-referenced assemblies

I recently asked a question in the WPF forums about loading xaml components from unreferenced assemblies, using Application.LoadComponent() API. This is a useful scenario especially if you are developing a plugin architecture for your application. Zhou Yong from the forums replied with a useful tidbit, which I will document in this blog post.

Application.LoadComponent() is used to create the object tree from a xaml file (or rather a compiled .baml file). This is useful especially if you want to delay the instantiation of a xaml component until runtime. Typically you would have the xaml files inside your own application assembly, in which case the API works without any extra work. You could also keep the xaml files in a custom-control-library, add a project-reference to this library and still use the API. It would work without any problems. The interesting case comes when you don’t have a project-reference available at compile-time. This is when the API doesn’t work. For plugin development it is the most common case.

Fortunately there are couple of different ways in which you can make it work. For the API to work, you need to have the assembly that contains the xaml file, to be loaded in your AppDomain. If you note the previous two cases: one where the xaml file is part of the application-assembly and the other where the xaml file is contained in a referenced assembly, both of them ensure that the assembly will be loaded into the AppDomain when you make the call. Now lets take the case where you don’t have any reference to the assembly at compile time.

The different approaches

Here I will call ”assembly” as the DLL file that contains the xaml.

1] Assembly is in the same directory as the application (EXE)

  • This is the case where all your plugin assemblies are intended to be in the application-directory itself.
  • Load the assembly into the AppDomain using Assembly.LoadFile(“<path to assembly>”) or Assembly.Load(“<assembly-name>“)
  • Make the API call Application.LoadComponent(new Uri(”/<assembly-name>;component/<xaml-file-name>.xaml”, UriKind.Relative))
  • [EDIT] Note that this case works because by default the CLR will probe in the current directory for assemblies to resolve Types

2] Assembly is in a sub-directory under the application directory

  • This will be your typical case for plugin development. Generally you call this sub-directory as “/plugins” or something similar. It will contain all your plugin Dlls.
  • Add an App.config file to your application (the startup project) and put the following xml-snippet in it. The key part here is the <assemblyBinding/> tag, which tells the CLR that there are other places under the application-directory for resolving Type references. If you have more sub-directories to probe, add them by separating with semi-colons (;)
<?xml version="1.0"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="plugins;special_plugins"/>
</assemblyBinding>
</runtime>
</configuration>
  • Load the assembly into the AppDomain and then make Application.LoadComponent() call.

3] A possible third approach involves using the Reflection API. Note that here you would not be using Application.LoadComponent() at all. Instead you would make a call to Activator.CreateInstance() for loading the component. You still have to load the assembly into the AppDomain before calling Activator.CreateInstance(). However I understand that this has performance implications (the forum post has more information). In short, the reflection API is too generic, so it has to do a bunch of checks before it can resolve the type. The code will look something like:

Assembly asm = Assembly.LoadFile(@"C:CustomControlLibrary1.dll");
Type type = asm.GetType("CustomControlLibrary1.UserControl1");
UserControl control = Activator.CreateInstance(type) as UserControl;

The only advantage here is that you are not limited to assemblies only under the application directory (or sub-directories). So you could keep them in some other known-directory and load from there.

Loading XAML components from un-referenced assemblies is a fundamental requirement during plugin-development. Although there are three different approaches, I personally prefer approach# 2]. It is versatile (ie. serves the typical plugin development scenario) and also most performant.

[Edit] Make sure you also check out this blog post about a possible issue using Application.LoadComponent(). I ran into this sometime back.

Application.LoadComponent() from un-referenced assemblies
Pavan Podila
Pavan Podila
November 17th, 2006