Search code examples
c#wpfcodedom

CodeDom using WPF - error at runtime


I have a project where I compile a lot of files in memory using Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider

My problem happened when I started to try to use wpf windows.

I am able to get the in-memory assembly to compile, but when I go to bring up the window I get:

System.Exception: The component 'Dynamic.DragonListForm' does not have a resource identified by the URI '/ScriptCode;component/wpf_ui/dragonlistform.xaml'. at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)

NOTE: I compile by adding a list of all the .cs files in a particular folder

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

I also add dll references needed to make it work.

NOTE: Thanks to Reed, I was able to get it working well enough for my needs by doing:

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

In my project this is good enough. I have a .NET app that I use for executing voice commands. In general, I have it so I can recompile assembly changes in memory as I change voice commands. I imagine some of this won't work with WPF but I am now able to use WPF windows in my in-memory assembly.


Solution

  • The problem is that WPF files aren't just C#, they're also the XAML, which then gets compiled in a separate MSBuild task into BAML resources and included as embedded resources.

    If you wanted to support some version of this, you'd need to include all of the referenced xaml as resources. See this post for details on how to do that using CodeDom.

    Once that was done, you'd have to also make sure that you're using a compatible mechanism for loading the types. The "normal" way C# compiles xaml/xaml.cs files won't work in your situation, as it requires the resources to be precompiled to baml. You'd have to effectively "rewrite" the code behind for the C# types to use a different mechanism of loading the XAML - typically this would be done by using XamlObjectReader and XamlObjectWriter to read the xaml contents and "write them" into the object during the InitializeComponent pass.