2017-01-31 8 views
3

У меня есть проект, где я компилировать много файлов в памяти с помощью Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProviderCodeDom с помощью WPF - ошибки во время выполнения

Моя проблема случилась, когда я начал пытаться использовать МОФ окна.

Я могу получить сборку в памяти для компиляции, но когда я иду, чтобы открыть окно я получаю:

System.Exception: Компонент «Dynamic.DragonListForm» не имеет ресурс, идентифицированный URI '/ScriptCode ;component/wpf_ui/dragonlistform.xaml'. в System.Windows.Application.LoadComponent (Component Object, Uri resourceLocator)

Примечание: Я компилирую, добавив список всех файлов .cs в определенной папке

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

Я также добавить dll, необходимые для его работы.

Примечание: Благодаря Рид, я был в состоянии заставить его работать достаточно хорошо для моих потребностей, выполнив:

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

В моем проекте это достаточно хорошо. У меня есть приложение .NET, которое я использую для выполнения голосовых команд. В общем, у меня есть это, поэтому я могу перекомпилировать изменения сборки в памяти при изменении голосовых команд. Я предполагаю, что некоторые из них не будут работать с WPF, но теперь я могу использовать окна WPF в моей сборке в памяти.

ответ

4

Проблема в том, что файлы WPF - это не только C#, но и XAML, который затем скомпилируется в отдельной задаче MSBuild в ресурсы BAML и включается в качестве встроенных ресурсов.

Если вы хотите поддержать некоторую версию этого, вам нужно будет включить все ссылки на xaml в качестве ресурсов. См. this post для получения подробной информации о том, как это сделать с помощью CodeDom.

Как только это будет сделано, вам также необходимо убедиться, что вы используете совместимый механизм для загрузки типов. «Обычный» способ C# компилирует файлы xaml/xaml.cs в вашей ситуации не будет работать, так как он требует, чтобы ресурсы были предварительно скомпилированы в baml. Вам нужно было бы эффективно «переписать» код для типов C# для использования другого механизма загрузки XAML - как правило, это можно было бы сделать, используя XamlObjectReader и XamlObjectWriter, чтобы прочитать содержимое xaml и «записать их» в объект во время InitializeComponent проход.

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, который отображается в сообщении об ошибке, например:

Компонент «Dynamic.DragonListForm» не имеет идентификатора ресурса ed URI '/ScriptCode;component/wpf_ui/dragonlistform.xaml'.на

Метод расширения:

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