Load and Run WPF DLL into Another WPF exe

2020-06-27 06:02发布

问题:

My main issue is as I stated in title.

WPF_APP1 --> I created dll of this wpf project after excluding App.xaml
WPF_APP2 --> Normal WPF exe. which needs to run the above WPF_APP1 dll and open the WPF_APP1 MainWindow form using reflection.

Why I am saying for reflection is - WPF_APP2 first get the latest WPF_APP1.dll then open so can not add the reference of dll. have to use the Reflection only.

When I use the above dll in cmd project its okay. it open the CMD window then launch the WPF_APP1 MainWindow as Window form.

But Now I need to open this window form not in cmd, in WPF_APP2.

Please help me out.

CMD project use the below code to open the WPF_APP1 MainWindow.

    static void Main(string[] args)
    {            
        Thread t = new Thread(ThreadProc);
        t.SetApartmentState(ApartmentState.STA);
        t.IsBackground = true;
        t.Start();

        Console.ReadLine();                   
    }


    private static void ThreadProc()
    {
        string loc = new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName
                      + "\\AutoUpdateTesting.dll";

        Assembly dll = Assembly.LoadFile(loc);

        foreach (Type type in dll.GetExportedTypes())
        {                
            if (type.Name.Equals("MainWindow"))
            {                   
                dynamic n = null;
                n = Activator.CreateInstance(type);
                n.InitializeComponent();
                System.Windows.Application apprun = new System.Windows.Application();
                apprun.Run(n);

                break;
            }
        }

    }

I can not use line -

    System.Windows.Application apprun = new System.Windows.Application();

In WPF_APP2 because of AppDomain(found this reason on google). Try other alternative but no luck.

Please have a look and share your knowledge. :)

waiting for your comments and reply.

Thanks

回答1:

Load WPF window from forms application:

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        ThreadProc();
        Application.Run(); // Keep on running!
    }

    private static void ThreadProc()
    {
        if (System.Windows.Application.Current == null)
            new System.Windows.Application();
        try
        {
            string assemblyName = string.Format("{0}\\AutoUpdateTesting.dll", new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName);
            System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
            {
                Window wnd = LoadAssembly(assemblyName, "OtherWindow");
                wnd.Show();
            }));
        }
        catch (Exception ex)
        {
            System.Diagnostics.Trace.WriteLine(string.Format("Failed to load window from{0} - {1}", "OtherWindow", ex.Message));
            throw new Exception(String.Format("Failed to load window from{0} - {1}", "OtherWindow", ex.Message), ex);
        }
    }

    private static Window LoadAssembly(String assemblyName, String typeName)
    {
        try
        {
            Assembly assemblyInstance = Assembly.LoadFrom(assemblyName);
            foreach (Type t in assemblyInstance.GetTypes().Where(t => String.Equals(t.Name, typeName, StringComparison.OrdinalIgnoreCase)))
            {
                var wnd = assemblyInstance.CreateInstance(t.FullName) as Window;
                return wnd;
            }
            throw new Exception("Unable to load external window");
        }
        catch (Exception ex)
        {
            System.Diagnostics.Trace.WriteLine(string.Format("Failed to load window from{0}{1}", assemblyName, ex.Message));
            throw new Exception(string.Format("Failed to load external window{0}", assemblyName), ex);
        }
    }
}

That does the trick for forms! Remember that you need to add references to the base WPF assemblies(PresentationCore, WindowBase+++)

WPF loading external window (Read your post wrong, so here you have wpf to wpf as well)

public partial class App : Application
{
    App()
    {
        Startup += App_Startup;
    }

    void App_Startup(object sender, StartupEventArgs e)
    {
        try
        {
            string assemblyName = string.Format("{0}\\AutoUpdateTesting.dll", new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName);
            Window wnd = LoadAssembly(assemblyName, "OtherWindow");
            wnd.Show();
        }
        catch (Exception ex)
        {
            System.Diagnostics.Trace.WriteLine(string.Format("Failed to load window from{0} - {1}", "OtherWindow", ex.Message));
            throw new Exception(String.Format("Failed to load window from{0} - {1}", "OtherWindow", ex.Message), ex);

        }
    }

    private Window LoadAssembly(String assemblyName, String typeName)
    {
        try
        {
            Assembly assemblyInstance = Assembly.LoadFrom(assemblyName);
            foreach (Type t in assemblyInstance.GetTypes().Where(t => String.Equals(t.Name, typeName, StringComparison.OrdinalIgnoreCase)))
            {
                var wnd = assemblyInstance.CreateInstance(t.FullName) as Window;
                return wnd;
            }
            throw new Exception("Unable to load external window");
        }
        catch (Exception ex)
        {
            System.Diagnostics.Trace.WriteLine(string.Format("Failed to load window from{0}{1}", assemblyName, ex.Message));
            throw new Exception(string.Format("Failed to load external window{0}", assemblyName), ex);
        }
    }
}

Hope it helps!

Cheers

Stian



回答2:

Not an answer, but a suggestion:

I would change :

foreach (Type type in dll.GetExportedTypes())
{                
    if (type.Name.Equals("MainWindow"))
    {                   
        dynamic n = null;
        n = Activator.CreateInstance(type);
        n.InitializeComponent();
        System.Windows.Application apprun = new System.Windows.Application();
        apprun.Run(n);

        break;
    }
}

with:

// replacing the loop, brackets and break with:
var main_win = dll.GetExportedTypes().Where(t => t.Name.Equalts("MaindWindow");

dynamic n = null;
n = Activator.CreateInstance(type);
n.InitializeComponent();
System.Windows.Application apprun = new System.Windows.Application();
apprun.Run(n);

Let linq worry about it, and make your code easier to read and maintain.



标签: c# wpf dll