Search code examples
c#wpfwinformsunity-game-enginewindowsformshost

Embed one Unity .exe file into multiple WPF Pages


I have a WPF application embedding a Unity3D application similar to this: Embed Unity3D app inside WPF application

The embedding is done into a WPF Page using WindowsFormsHost and WinForms:Panel

<WindowsFormsHost><WinForms:Panel x:Name="MyGame"/></WindowsFormsHost>

Now, my application requires me to show different Scenes of my Unity.exe on different pages in my WPF app. For example on Page1 the Unity.exe displays Scene1, and on Page2 the Unity.exe displays Scene2. I have a TCP communication to switch between scenes.

One way to achieve this would be to kill the process running Unity.exe and restarting it every time the user navigate to a new page. However, this will cause the user to wait for the Unity.exe to load every time. Therefore, is it possible to embed an .exe file running on one process and displayed it on multiple WPF pages? Somehow, I like to have the process running in the background when the user navigates to ordinary pages without the embedding.

My intuition says that embedding the .exe file into a User Controls might be a possible solution, but I did not find sufficient information on this so far.


Solution

  • I am the author of one of the answers on another related question on Stack Overflow. I made a repository which is a fork of your repository that has the behaviour as you intended.

    I saw you like to work with Frames and that's okay, but because of that you had two unwanted behaviours I fixed for you in regard to the original repository.

    • The fact that the navigation panel was still showing up can be avoided with the attribute NavigationUIVisibility="Hidden" in the Frame of the MainWindow.xaml .

    • You also told me via e-mail that "the second time" a button was clicked, the WinformsHost was not showing up. This was because the changing the content of the Frame is not by definition triggering a refresh. You can force this refresh by the line Page2_UnityFrame.NavigationService.Refresh(); and similar for Page3 and Page4.

    I tested with this code and now I think the behaviour is exactly as you wanted. Nevertheless, I would like to take the opportunity to give some extra advice regarding this version of the application.

    • I took the liberty to put your Unity-files (and related folders) and relocated them to a folder called All_Unity_Files . Than, in a post-build-event of the Container-project, I can specify that these Unity-files (and folders) need to be copied to the target directory. This is done via the command: xcopy "$(SolutionDir)..\All_Unity_Files" "$(TargetDir)" /s /y /r /d . So if you now download this code or clone the reposity, if the build succeeds, the required Unity files are automatically in the right directory to launch the application.
    • Second, I also renamed the Frames of the pages to Page1_UnityFrame , Page2_UnityFrame and so on. Before, these frames and the main frame in MainWindow.xaml all had the same x:Name (UnityFrame) and that is something that I would not recommend. If you than change in the code-behind, it is difficult to determine which frame you are getting or setting and as a consequence, more difficult to debug.
    • As a third and final remark, I would recommend to inform yourself about the possibility of data binding via MVVM. This will minimalize the amount of code in the code-behind and especially if your application will grow, it will be easier to maintain.