Type mismatch when loading an embedded class library in WPF

Viewed 152

I have an application for which I use WPF. The application is dependent on a few libraries which I load as embedded resources. Mostly, this works like a charm.

Things go wrong when I try to add my own class library as an embedded resource as well (I'd like to keep the executable standalone). The library still loads and I am able to use all classes and controls it contains. What I am unable to do, however, is to define styles for these controls in any resource dictionary (e.g. app.xaml).


When I try to do something like this:
App.xaml:

<ResourceDictionary x:Class=....
                    xmlns:library="clr-namespace:myNamespace;assembly=assemblyName">
    <Style x:Key="Test" TargetType="{x:Type library:myControl}" />
</ResourceDictionary>

Main.xaml:

<Window x:Class=....
        xmlns:library="clr-namespace:myNamespace;assembly=assemblyName">
    <library:myControl style="{staticresource Test}" />
</Window>

I get the following error:
InvalidOperationException: 'myControl' TargetType does not match type of element 'myControl'.

Why is this? Can I somehow make clear that in fact, both myControl are the same type?


There are a few things that do work, but arent viable options for me. One is setting the style directly in Main.xaml:

<Window x:Class=....
        xmlns:library="clr-namespace:myNamespace;assembly=assemblyName">
    <library:myControl>
        <library:myControl.Style>
            <Style TargetType="{x:Type library:myControl}" />
        <library:myControl.Style/>
    </library:myControl>
</Window>

which works fine. However, I have hundreds of such controls which all need to implement largely the same style. It wouldn't want to repeat the same style in every window or control including myControl.


Something else that works to my surprise is writing the library data to a file, and then loading it. e.g. if I do:

var assembly = Assembly.GetExecutingAssembly();
string libraryName = "assemblyName.dll";
string library = assembly.GetManifestResourceNames().Where(s => s.EndsWith(libraryName)).First();
using (Stream stream = assembly.GetManifestResourceStream(library))
using (FileStream FS = File.Create(fullPath)) 
    stream.CopyTo(FS);
Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), libraryName));

all my problems are gone. The catch is that now the assembly's loaded and I cannot delete the file I've just created. I've tried bypassing this by loading it into a separate domain and other suggestions given in questions such as this one, but to no avail: I cannot delete the loaded assembly even after unloading the domain it's loaded in.

1 Answers

Upon inspecting the target types of my styles (Style.TargetType) and the types of the controls (control.GetType()) in my wpf window, I found a few differences:

  • The RuntimeType.Assembly.CodeBase is different when loading the library as an embedded resource: assemblyName.dll for the type of the controls, and application.exe for the TargetType of the styles.
  • A few pointers also differ between the types: RuntimeType.Assembly.m_assembly and MemberInfo.Module.m_pData. This implies to me that the library is actually loaded twice in differing parts of memory, hence it can't be guaranteed that both types are the same.

This explains why writing the assembly to a file, and then loading it would solve the issue: both types then have Assembly.CodeBase pointing to assemblyName.dll and the pointers also nicely match.


Ultimately I found the following workaround:

By reloading the App.xaml ResourceDictionary in Window.Resources (MainWindow.xaml), the types in the ResourceDictionary are guaranteed to be the same as the type in the controls and everything works accordingly. This causes no issues for me as my application only has a single window, although it does seem a little sloppy to be loading the same ResourceDictionary twice (once application-wide, once in the scope of the window). The real question remains why the assembly codebase is different when loading app.xaml than it is for the rest of the application's lifespan.

Related