创建多个 .xaml 视图

Creating multiple .xaml Views

我想创建名为 view.xaml 的 .xaml UserControl 的多个实例,它位于程序集 dir1\asm.dlldir2\asm.dll 中,而 asm.dll 是相同的程序集仅在版本号和 view.xaml.

的实现上有所不同

我有以下设置:

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);
    }

我收到以下异常:

带有异常详细信息

我能够在我的 view.xaml:

的 InitializeComponent() 方法中跟踪到这个位置的问题

更具体地说,在 InitializeComponent() 中:

嗯,这很有趣...

两个程序集具有相同的资源 URI。如果 Uri 包含版本但 VS 似乎没有把它放在那里,它会起作用。最后加载哪个(asm1 或 asm2)似乎能够使用 non-versioned Uri 而不会崩溃。

如果,而不是: "/ProblemEditor;component/problemeditor.xaml"

您有:“/ProblemEditor;v1.0.0.0;component/problemeditor.xaml”和“/ProblemEditor;v2.0.0.0;component/problemeditor.xaml"

那就没问题了

我为重建您的环境所做的是:

  1. 使用用户控件 (usercontrol1) 创建用户控件库
  2. 编译并复制dll(已签名的dll)
  3. 更改版本和用户控件(文本块显示 "version 2" 而不是 "version 1")
  4. 编译并复制dll(已签名的dll)

然后我:

  1. 使用 Reflexil 插件启动了 Telerik 的 JustDecompile(您可以从 JustDecompile 的插件管理器中获取它)。
  2. 已加载 dll
  3. 在 InitializeComponent 方法中找到了 Uri
  4. 修改了 Uri 以包含与 dll 匹配的版本
  5. 对 dll 做了 "save as"。由于它们已签名,而我们只是修改了它们,Reflexil 延迟对其进行了签名,但提出删除强名称或 re-sign with key(当然,您必须提供 .snk 密钥文件)。我刚刚 re-sign 编辑了它们,因为我有密钥文件。

那么你上面的代码就可以工作了!作品!成功了!

我希望这是您可以接受的解决方案。如果其他人有办法在不破解 dll 的情况下解决这个问题,我也很想知道。

经过一个星期的折腾和折腾,我终于找到了问题的原因和解决方法。

问题出在自动生成的 *.g.i.cs 文件中,该文件由 UserControlInitializeComponent() 方法调用,如下所示:

此文件生成一个字符串(资源定位器),表示 xaml 组件的路径,如下所示:

现在,如果您有 同一程序集的多个版本 并且两个版本都包含相同的 xaml 文件,WPF 不知道要实例化什么 xaml-file,因为资源定位器只引用程序集的名称而不是它的版本。

这导致 TargetInvocationException,即

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

如下:

对此的简单(但绝对不是显而易见的)解决方案是将程序集的版本添加到此资源定位器。这可以通过添加 <AssemblyVersion>-tag 修改项目的构建文件来实现,如下所示:

致谢名单: