使用WPF的CodeDom - 运行时出错

时间:2017-01-31 17:12:32

标签: c# wpf codedom

我有一个项目,我使用Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider

在内存中编译了很多文件

当我开始尝试使用wpf windows时,我的问题就出现了。

我能够编译内存中的程序集,但是当我打开窗口时,我得到:

  

System.Exception:组件' Dynamic.DragonListForm'不具有   由URI标识的资源   ' /脚本代码;组件/ wpf_ui / dragonlistform.xaml&#39 ;.          在System.Windows.Application.LoadComponent(对象组件,Uri resourceLocator)

注意:我通过添加特定文件夹中所有.cs文件的列表进行编译

objCompileResults = objCodeCompiler.CompileAssemblyFromFile( objCompilerParameters, files.ToArray() );

我还添加了使其工作所需的dll引用。

注意:感谢Reed,我能够通过以下方式让它满足我的需求:

 List<string> bamlFiles = Directory.GetFiles( directoryPath, "*.baml", SearchOption.AllDirectories ).ToList();
 bamlFiles.ForEach( x => objCompilerParameters.EmbeddedResources.Add( x ) );

在我的项目中,这已经足够了。我有一个用于执行语音命令的.NET应用程序。一般来说,我有它所以我可以在更改语音命令时重新编译内存中的程序集更改。我想其中一些不能使用WPF,但我现在能够在内存中使用WPF窗口。

2 个答案:

答案 0 :(得分:4)

问题是WPF文件不仅仅是C#,它们也是XAML,然后在单独的MSBuild任务中编译成BAML资源并作为嵌入资源包含。

如果您想支持某些版本,则需要将所有引用的xaml作为资源包含在内。有关如何使用CodeDom执行此操作的详细信息,请参阅this post

完成后,您还必须确保使用兼容机制来加载类型。 C#编译xaml / xaml.cs文件的“正常”方式在您的情况下不起作用,因为它需要将资源预编译为baml。您必须有效地“重写”C#类型背后的代码,以使用不同的加载XAML的机制 - 通常这可以通过使用XamlObjectReaderXamlObjectWriter来读取xaml内容和在InitializeComponent传递过程中“将它们写入”对象。

答案 1 :(得分:0)

另一个非常有用的信息是:The component does not have a resource identified by the uri

由此我创建了一个可以这样调用的扩展方法:

 // https://stackoverflow.com/questions/7646331/the-component-does-not-have-a-resource-identified-by-the-uri
 this.LoadViewFromUri( @"/ScriptCode;component/wpf_ui/spywindowviewer.xaml" );
 // InitializeComponent();

注意:我只是使用显示在错误消息中的uri,例如:

组件&#39; Dynamic.DragonListForm&#39;没有由URI &#39; / ScriptCode; component / wpf_ui / dragonlistform.xaml&#39; 标识的资源。在

扩展方法:

using System;
using System.IO.Packaging;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Navigation;

namespace Extensions
{
   public static class WpfWindowExtensions
   {
      // https://stackoverflow.com/questions/7646331/the-component-does-not-have-a-resource-identified-by-the-uri
      public static void LoadViewFromUri( this Window window, string baseUri )
      {
         try
         {
            var resourceLocater = new Uri( baseUri, UriKind.Relative );
            // log.Info( "Resource locator is: ")
            var exprCa = ( PackagePart )typeof( Application ).GetMethod( "GetResourceOrContentPart", BindingFlags.NonPublic | BindingFlags.Static ).Invoke( null, new object[] { resourceLocater } );
            var stream = exprCa.GetStream();
            var uri = new Uri( ( Uri )typeof( BaseUriHelper ).GetProperty( "PackAppBaseUri", BindingFlags.Static | BindingFlags.NonPublic ).GetValue( null, null ), resourceLocater );
            var parserContext = new ParserContext
            {
               BaseUri = uri
            };
            typeof( XamlReader ).GetMethod( "LoadBaml", BindingFlags.NonPublic | BindingFlags.Static ).Invoke( null, new object[] { stream, parserContext, window, true } );
         }
         catch( Exception )
         {
            //log
         }
      }
   }
}