Search code examples
c#wpfxamldllresourcedictionary

Runnable Dll created from WPFapplication doesn't find referenced ResourceDictionary


I've searched now for a while and found no solution for specific problem.

At first I've developed a WPF-Application with several Projects and UserControls using the same ResourceDictionary in more than 1 of the Projects. So I sourced the Resource dictionary out in a single Project only holding the dictionary.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WPFGlobalResources;assembly=WPFGlobalResources"
                    >

    <!--Here are placed some styles I use globally -->    
    
</ResourceDictionary>

In many of my Windows and UserControls I referenced WPFGlobalResources inside the Project and added

<Window.Resources> or UserControl.Resources
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/WPFGlobalResources;component/GlobalWpfResources.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

in the beginning of the xamls.

As long as I am working with an executable application everything just works fine and all resources can be loaded.

Now I needed a runnable Dll-Version of this Application to register it in Windows Registry. To do this, I threw the App.xaml out of my Project and turned it into a classlibrary, as I could found it described in many Google sites.

Registered there I can call it out of a CAD-Program - in this program it uses the call DLL MainApplication.exec 1 , which needs the following methods in my DLL-Project to get a new EntryPoint(I used a extra class for it):

public class Exec
{
    public short vcExtStartUp(ref string Directory, string ExtensionName)
    {   //I don't use this method
        return 1;

    }

    public short vcExtMenuExec(ref int MenuID)
    {   //this is what I need to run a WPF Application
        Application app = new Application();

        app.StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative); ;
        
        app.Run(new MainWindow());
        return 1;
    }
}

Here I only need the second method, as you can see. My original Project threw some errors here so I reduced my Problem as much as I can, using only the Project containing the WPFGlobalResources and one Project containing an almost empty MainWindow containing a button, using a style from the dictionary, and a reference to the Project of my dictionary.

As long as I comment out the call of the mergedDictionary in the beginning of the MainWindow.xaml, everything works fine (of course I don't have the buttonstyle then). If I try to use the ResourceDictionary, my CAD-Program crashes while calling the DLL and debugger leads me to the error: (Hope I translated it correctly)

IOException - Additional Information: Assembly.GetEntryAssembly() returns NULL. Define Application.ResourceAssembly-Property or use the Syntax "pack://application:,,,/assemblyname;component/" to define the assembly the resource should be loaded from.

Ok, then I've added Application.ResourceAssembly = typeof(MainWindow).Assembly; just behind new Application(). Now the Debugger gets a little bit more forward, but stopping again with the error:

Exception in MainWindow.xaml linenumer12 ... -> InnerException {"File or Assembly "WPFGlobalResources, Culture=neutral" or a dependency of it couldn't be found. System can't find specified file.":"WPFGlobalResources, Culture=neutral"} System.Exception {System.IO.FileNotFoundException}

I've also tried to add

System.Uri resourceLocater = new System.Uri("/MainApplication;component/VisiDockedMainWindow.xaml", System.UriKind.Relative);

System.Windows.Application.LoadComponent(resourceLocater);

but with no success, still the same error.

Now I can't find a solution to make it work. Is it possible that pack://application... now targets my CAD-Program as application and not the Location of my DLL, where the WPFGlobalResources.dll (and every other dll) is located? And how can I change that, I couldn't find a URI for this usecase in MSDN.

Next thing I have to try is dumping my WPFGlobalResources and adding the styles to every single Window/Usercontrol, but I hope that is not the only solution??? Produces a lot of redundant code...


Solution

  • Okay, after trying alot I meanwhile found a solution:

    The point is, that while executing the xaml-Code of the MainWindow, references seem not to be loaded. The solution is simply adding a:

    Assembly resAssembly = Assembly.Load("WPFGlobalResources");
    

    before using app.Run. This seems to preload the external reference and then it can be found.

    Interesting hint: In this case it is even better to leave the WPF-Application without any changes (still executable with App.xaml stuff) and add an extra Classlibrary-Project to create the dll. And then you can add a class starting your WPF-Application (of course you have to reference the WPF-Projekt and the ResourceDictionary-Projekt first):

    public class Exec
    {
    
        public short vcExtStartUp(ref string Directory, string ExtensionName)
        {
            return 1;
    
        }
    
        public short vcExtMenuExec(ref int MenuID)
        {
            Thread thread = new Thread(() =>
            {
                WpfTestAppl.App app = new WpfTestAppl.App();
    
                // Loading of ResourceAssemblys                
                Assembly resAssembly = Assembly.Load("WPFGlobalResources");
    
    
                app.Run(new WpfTestAppl.MainWindow());
    
            });
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
    
            return 1;
        }
    }
    

    And now it finally works :-)