📜 ⬆️ ⬇️

We are friends with XNA and WPF

First, I will answer the question "Why should they be friends." The answer is simple - WPF is good for user interfaces, XNA for complex 3D graphics and if you make a client application with a complex interface and 3D elements in it, then a bunch of XNA & WPF is just for you.
I will illustrate the article on the example of a simple media player that I am writing now.

So, we have a cover scroller written in XNA. It looks like this:

We also have a WPF project for a future media player, here’s a screenshot of it:

Our task is to put the first into the second. We will do the same as we did earlier with applications on Windows Forms: pass the handle to the control of the Game class to the control on top of which we will draw. But there is one small problem: in WPF, only windows have handles. However, this problem is easily solved: add a Windows FormsHost control to the window and place the panel (Panel) from the System.Windows.Forms namespace into it. And here we will transfer the handle of this panel to the game designer. So, we act in order:
  1. Combine XNA and WPF projects in one solution
  2. We delete the Program.cs file from the XNA project and in the project properties we change the type from the Windows application to the class library.
  3. Add Microsoft.Xna.Framework.Game to the WPF project References
  4. Add the IntPtr handle parameter to the game constructor declaration
  5. In the WPF form constructor, create an instance of the game class and pass it the handle to the panel and call the Run () method on the game in a separate thread
  6. During the initialization of the device, assign our handle

I will explain the last point:
IntPtr Handle;
public MainGame( IntPtr handle)
Handle = handle;
graphics = new GraphicsDeviceManager( this );
graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(PreparingDeviceSettings);

public void PreparingDeviceSettings( object sender, PreparingDeviceSettingsEventArgs e)
e.GraphicsDeviceInformation.PresentationParameters.DeviceWindowHandle = Handle;

* This source code was highlighted with Source Code Highlighter .

Great, our “game” is drawn into the panel reserved for it, but there are a few points that this solution does not suit me:

We will solve these problems. For this, I propose to stop using the game class and write a small device manager. We will have to manually initialize the device, repaint the scene by timer, respond to the resizing of the control and its destruction. We transfer the control to the manager, on which we will draw, subscribe to the resize and draw control events, create a device and a timer, according to which we will trigger the Update and Draw events. You can view the source code of the graphical manager here or in the attached project. We just have to deal with the panel. It turns out you just need to apply the appropriate styles and the panel will stop blinking. The only inconvenience is that the access modifier of the SetStyle method is protected. Well, nothing, inherit from the panel and in the designer apply the styles we need. The source code of the optimized panel is simple to disgrace:

public class OptimizedPanel : Panel
public OptimizedPanel()
: base ()
this .SetStyle(ControlStyles.UserPaint, true );
this .SetStyle(ControlStyles.Opaque, true );

* This source code was highlighted with Source Code Highlighter .

So, everything is ready with us, we start the project and see that everything works as it should: the panel does not blink, the dimensions change correctly, the application does not open additional windows.
Here you can download the initial draft application with a bunch of WPF & XNA. Well, that's what happened with me:

Source: https://habr.com/ru/post/101165/

All Articles