XNA+WPF solution worked

Cory Petosky‘s website

Edit 11/17/2010:

While this article‘s XNA+WPF solution worked when I wrote it, in mid 2009, it no longer functions. This solution might get you halfway there, but I have not researched the other half as I am no longer regularly programming in XNA. Judging from the comments I‘ve been getting for the last couple years, this might not even be possible.



We‘re writing Kung-Fu Kingdom using a platform called XNA. I‘ve worked with a lot of game frameworks, and this particular one has a lot of advantages, but the two big ones are:

  1. You can write code in any .NET language, which means you get to use C#, a very nice programming language with a lot of great features.
  2. You can compile your project for the XBox 360 Community Games platform.

I‘m compelled to note that the primary disadvantage of XNA is that it‘s currently (and will be for the foreseeable future) Windows only.

Now, XNA is great, and it‘s based on DirectX, the Microsoft graphics layer that Windows has used for ages. But it‘s new, and like everything else Microsoft does, when stuff is new, it doesn‘t work well with others. In particular, they‘ve also recently released a new GUI framework called WPF. It‘s desireable in a lot of cases to mix your game framework with your GUI framework, so you can, say, make a nice looking set of tools to build your game with.

XNA and WPF don‘t play together nicely yet. They want to, they intend to, and Microsoft is working on making them friends, but currently it requires a set of tightly-coded leg irons to keep them together. Here‘s my technique for getting one inside the other.

Step 1: Make a game

This is probably the hardest step, but I know you can do it! It‘s beyond the scope of this article though. If you just feel like fooling with this, you can make a simple game that just redraws the screen background to a random color every frame.

Step 2: Make a WPF Window

Make a new WPF project. As far as I can tell, there‘s no way to directly inject XNA into WPF, so we‘re going to use an intermediate layer. We‘ll add a WinForms host to our WPF window, and then inject our XNA game into that WinForms host. Here‘s the basic code for your WPF window:

<Window x:Class="EditorWPF.Editor"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
    Title="Editor" Height="Auto" Width="Auto">
    <DockPanel>
        <Menu Name="MenuBar" DockPanel.Dock="Top"/>
        <StatusBar Name="StatusBar" DockPanel.Dock="Bottom">
            <StatusBarItem>
                <TextBlock Name="statusText">Load or create a project to begin.</TextBlock>
            </StatusBarItem>
        </StatusBar>
        <WindowsFormsHost DockPanel.Dock="Bottom" Width="800" Height="600">
            <wf:Panel x:Name="RenderPanel"/>
        </WindowsFormsHost>
    </DockPanel>
</Window>

Be sure you‘ve referenced the System.Windows.Forms assembly for your project, or this won‘t work.

The menu and status bar are just to illustrate why we‘re doing this -- if we just put the XNA game by itself in the window, there would be no point to this technique. Anyway, now we have a WinForms Panel available to inject our XNA game into.

Step 3: Setup your game to accept Panel reference

Go into your Game class. We‘re going to edit the constructor to accept a single IntPtr argument called handle. The handle parameter is the internal memory handle of the panel we created above. However, we don‘t muck with the display heirarchy right in the constructor -- we add an event listener to the game‘s GraphicsDeviceManager for PreparingDeviceSettings, and muck with it then. Here‘s what your code should look like:

private IntPtr handle;
private GraphicsDeviceManager graphics;

public EditorGame(IntPtr handle) {
    this.handle = handle;
    graphics = new GraphicsDeviceManager(this);
    graphics.PreparingDeviceSettings += OnPreparingDeviceSettings;

    this.IsMouseVisible = true;
}

private void OnPreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs args) {
    args.GraphicsDeviceInformation.PresentationParameters.DeviceWindowHandle = handle;
}

Step 4: Set up your WPF Window to instantiate your Game

Usually, when you create an XNA project, it generates a simple Main function that just instantiates and runs your game for you. In this project, we‘re not going to use this. Instead, we‘re going to manually instantiate and run our game from our WPF window.

This isn‘t quite as simple as you might think. If we just call game.Run() somewhere, our window will stop responding until we end the game. Since we don‘t intend on ending the game until the WPF window is closed, this won‘t work. Instead, we have to spawn a second thread and run the game there. This is much easier than it sounds.

Open the code file underneath your XAML file and add these two lines to the bottom of your constructor:

IntPtr handle = RenderPanel.Handle;
new Thread(new ThreadStart(() => { game = new EditorGame(handle); game.Run(); })).Start();

And, of course, add a private game instance variable to your class:

private EditorGame game;

...and that‘s it! Run your WPF project and you should see your game between the status bar and the menu bar.

Optional: Breaking it down

In case you‘ve never used threads, lambda expressions, or anonymous objects before, let me break down that weird line above.

new Thread(
    new ThreadStart(
        () => {
            game = new EditorGame(handle);
            game.Run();
        }
    )
).Start();

Working from the inside out:

() => {
    game = new EditorGame(handle);
    game.Run();
}

This is a lambda expression, a C# 3.0 language feature. It‘s a shorthand way of defining a function. You can do exactly the same thing with C# 2.0‘s anonymous function feature, but lambda expressions are shorter and more elegant. You could also, of course, define a normal instance method instead of using an anonymous thing at all, but I like anonymous functions when the scope of that function is small and restricted to a single method. The following method is entirely equivalent to the above lambda expression:

private void MyFunction() {
    game = new EditorGame(handle);
    game.Run();
}

The ThreadStart constructor takes a delegate as an argument. A delegate is basically a way to treat a function or method as an object. By providing the lambda expression directly as an argument, the compiler treats it as a "function object" and passes it in to the ThreadStart constructor. If you‘re still confused or curious, search for C# delegates, and then search for C# lambda expressions.

Our statement now looks like this:

new Thread(
    new ThreadStart(
        MyFunction
    )
).Start();

The new ThreadStart there just instantiates a new ThreadStart object, just like every other new expression you‘ve ever used. In this case, we‘re never going to use that ThreadStart object again, so I define it anonymously -- that is, I don‘t assign it to a variable to be reused again later. This is equivalent to the following:

ThreadStart myThreadStart = new ThreadStart(MyFunction);
new Thread(myThreadStart).Start();

The new Thread call does the same thing, except it then invokes a method on the anonymous object created. Again, this is because I don‘t care to worry about the thread after I create it. In the end, this whole chunk is equivalent to what I first wrote:

public Editor() {
    IntPtr handle = RenderPanel.Handle;
    ThreadStart myThreadStart = new ThreadStart(MyFunction);
    Thread myThread = new Thread(myThreadStart)
    myThread.Start();
}

private void MyFunction() {
    game = new EditorGame(handle);
    game.Run();
}

I prefer mine myself:

IntPtr handle = RenderPanel.Handle;
new Thread(new ThreadStart(() => { game = new EditorGame(handle); game.Run(); })).Start();

But both approaches are "correct." There are many people who would advocate the longer approach, arguing that it‘s easier to read and maintain. I disagree, but now you have the option to include either based on your personal bias.

Originally posted July 8, 2009.

Copyright 2012 Cory Petosky. Email me: [email protected]

时间: 2024-10-25 23:44:31

XNA+WPF solution worked的相关文章

afterTextChanged() callback being called without the text being actually changed

afterTextChanged() callback being called without the text being actually changed up vote8down votefavorite I have a fragment with an EditText and inside the onCreateView() I add a TextWatcher to the EditText. Each time the fragment is being added for

Failed to start session after upgrade to 14.04

https://ubuntuforums.org/showthread.php?t=2217895 Thread: Failed to start session after upgrade to 14.04 Thread Tools Display April 19th, 2014 #1 prashanta2 prashanta2 is offline 5 Cups of Ubuntu Join Date Feb 2014 Location Alajuela, Costa Rica Beans

LiangNa Resum

LiangNa 220 AnShan Street, YangPu, NY 99999 18321657539 18321657539 @163.com OBJECTIVE: Seeking a position to contribute my skills and educational background in the field of Information Technology and Computer Science AREAS OF INTEREST: .NET Technolo

[转] --- Error: “A field or property with the name was not found on the selected data source” get only on server

Error: “A field or property with the name was not found on the selected data source” get only on server up vote4down votefavorite2I publish my project without any warning on local iis and it works correctly (localhost/[myprojectName]). so, i upload t

Perl,第一种后现代计算机语言

在吴涛大哥的博客上提到这篇文章<Perl,第一种后现代计算机语言>,原文链接:http://www.wall.org/~larry/pm.html 尝试翻译一下(已经发了邮件给Larry Wall,并且征得他的许可),有些句子太哲学,翻译不懂,作者是Perl的设计者,只供学习阅读使用.这里感谢我的英语八级同事在一些翻译上给予我很大的帮助.这篇东西拖的有点久,是我15年的计划之一,现在竟然把这个任务拖到了16年了,毕竟自己在这新的一年里有新的目标,所以会把旧的坑先给填上,后面的一些地方翻译的不是

Speeding up image loading in WPF using thumbnails

Technorati Tags: wpf, thumbnails, image, performance, slow, BitmapImage During a recent WPF session I needed to build a ListBox that showed a bunch of images loaded from an arbitrary directory. Thanks to WPF's data binding, this was trivial - I just

从0 开始 WPF MVVM 企业级框架实现与说明 ---- 第七讲 WPF 系统UI结构说明与AvalonDock的使用

说到WPF UI, 现在网上到处都有现成的UI, 我觉得还是AvalonDock算是比较适合企业级系统点,一般向ModernUI之类的只能做做小的App还凑合这用. 这边我分享一个DLL, AvalonDock.dll 访问密码 2f90 , 你们可以去下载,后面我们的demo中就是用这样一种UI结构. 其实对于一个系统的设计,我们要考虑到整体的业务逻辑,数据结构,业务需求与拓展等各方面,我这主要还是分模块一步步慢慢介绍下去,没有具体的项目,我就分模块去慢慢介绍. 这里就说Avalondock的

WPF依赖属性详解

WPF依赖属性详解 WPF 依赖属性 英文译为 Dependency Properties,是WPF引入的一种新类型的属性,在WPF中有着极为广泛的应用,在WPF中对于WPF Dependency Properties 的使用贯穿样式的使用,数据绑定,动画等等,在刚刚接触Dependency Properties的时候可能觉得有些奇怪,但是,当你了解他要解决的问题的时候,你可能就不觉得奇怪了.Dependency Properties第一个要解决的问题就是控件的属性共享问题,由于大部分的WPF控

WPF DATAGRID - COMMITTING CHANGES CELL-BY-CELL

In my recent codeproject article on the DataGrid I described a number of techniques for handling the updates to DataTables which are bound to the grid. These examples all worked on the assumption that you want to keep your database synchronised with