marc wellman
marc wellman

Reputation: 5886

Creating multiple .xaml Views

I want to create multiple instances of a .xaml UserControl named view.xaml, which resides in an assembly dir1\asm.dll and dir2\asm.dll whereas asm.dll is the same assembly that only differs in its version number and the implementation of view.xaml.

I have the following setup:

public void TestCreation() {

    Assembly asm = null;

    asm = Assembly.LoadFile("dir1\asm.dll");
    CreateView(asm); // works!

    asm = Assembly.LoadFile("dir2\asm.dll");
    CreateView(asm); // works!

    asm = Assembly.LoadFile("dir1\asm.dll");
    CreateView(asm); // FAILS!

}

public void CreateView(Assembly assembly)
    {
        Type type = assembly.GetTypes().First<Type>(t => t.Name.Equals("View"));

        UserControl view = (UserControl)assembly.CreateInstance(type.FullName, false, BindingFlags.CreateInstance, null, new object[] { }, null, null);
    }

I am getting the following Exception:

enter image description here

with the Exception detail

enter image description here

I was able to track the problem up to this location in the InitializeComponent() method of my view.xaml:

enter image description here

and more specificially within InitializeComponent():

enter image description here

Upvotes: 1

Views: 404

Answers (2)

marc wellman
marc wellman

Reputation: 5886

After a week suffering and laboring with this issue, I finally found both the reason for the problem and its solution.

The problem lies within the auto-generated *.g.i.cs file, which is called by the InitializeComponent() method of a UserControl, as seen by the following:

enter image description here

This file generates a string (a Resource Locator) that expresses the path to that xaml-component, as seen by the following:

enter image description here

Now, if you have multiple versions of the same assembly and both versions include the same xaml-file, WPF does not know what xaml-file to instantiate, because the Resource Locator only references the name of the assembly but not its version.

This results in a TargetInvocationException, saying that

{"The component 'MyNamespace.MyUserControl' does not have a resource identified by the URI '/MyAssembly;comoponent/myusercontrol.xaml'"}

as follows:

enter image description here

The simple (but most definitely not obvious) solution for this is to add the version of the assembly to this Resource Locator. This can be achieved by modifying the build-file of the project by adding the <AssemblyVersion>-tag as follows:

enter image description here

Credits for this go to:

Upvotes: 0

J.H.
J.H.

Reputation: 4322

Well, this was kind of fun...

Both assemblies have the same resource Uri. It would work if the Uri contained the version but VS doesn't seem to put that in there. Which ever one is loaded last (asm1 or asm2) seems to be able to use the non-versioned Uri without crashing.

If, instead of: "/ProblemEditor;component/problemeditor.xaml"

You had: "/ProblemEditor;v1.0.0.0;component/problemeditor.xaml" and "/ProblemEditor;v2.0.0.0;component/problemeditor.xaml"

Then there wouldn't be a problem.

What I did to recreate your environment was:

  1. Create a usercontrol library with a usercontrol (usercontrol1)
  2. Compile it and copy the dll (signed dll)
  3. Change the version and the user control (textblock says "version 2" instead of "version 1")
  4. Compile it and copy the dll (signed dll)

I then:

  1. Fired up Telerik's JustDecompile with the Reflexil plugin (you can get it from JustDecompile's Plugins Manager).
  2. Loaded the dlls
  3. Found the Uri's in the InitializeComponent methods
  4. Modified the Uri's to include the version that matches the dll
  5. Did a "save as" on the dlls. Since they were signed and we just modified them, Reflexil delay signed it but offered to remove the strong name or re-sign with key (you have to provide the .snk key file, of course). I just re-signed them since I have the key file.

Then your code above works! works! WORKS!

I hope this an acceptable solution for you. If anyone else has a way around this without hacking dlls, I'd be interested to know as well.

Upvotes: 1

Related Questions