• Advertisement
Sign in to follow this  

Embedding XNA game in a windows form....

This topic is 2999 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I need help! Seriously, I need help! Help me I broke apart my insides, help me I’ve got no soul to sell Help me the only thing that works for me, help me get away from myself I want to ... ... ... Enough N.I.N! My problem is pretty simple, I'm trying to get XNA to render to a panel, I tried using threading, but I guess windows forms are a little too threadsafe to do this :( Below is my implementation of the XNA side of things...
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace SystemEditor
{
    class SystemEditorDisplay : Microsoft.Xna.Framework.Game
    {
        GraphicsDevice graphicsDevice;
        public SystemEditorDisplay(IntPtr SurfaceHandle)
        {
            graphicsDevice = new GraphicsDevice(GraphicsAdapter.DefaultAdapter,
                DeviceType.Hardware,
                SurfaceHandle,
                new PresentationParameters());
        }
        protected override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }
        protected override void Draw(GameTime gameTime)
        {
            graphicsDevice.Clear(Color.Green);
            base.Draw(gameTime);
        }
    }
}
And this is how I am calling it from the form...
using System;
using System.Drawing;
using System.Windows.Forms;
namespace SystemEditor
{
    public class SystemEditor : Form
    {
        private SystemEditorDisplay sysEdDisp;
        private System.ComponentModel.IContainer components = null;
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        private System.Windows.Forms.MenuStrip systemEditorMenuStrip;
        private System.Windows.Forms.StatusStrip systemEditorStatusStrip;
        private System.Windows.Forms.ToolStrip systemEditorToolbarStrip;
        private System.Windows.Forms.Panel systemEditorDisplayPanel;
        private System.Windows.Forms.Timer systemEditorDisplayUpdater;
        private void InitializeComponent()
        {
            this.systemEditorMenuStrip = new System.Windows.Forms.MenuStrip();
            this.systemEditorStatusStrip = new System.Windows.Forms.StatusStrip();
            this.systemEditorToolbarStrip = new System.Windows.Forms.ToolStrip();
            this.systemEditorDisplayPanel = new System.Windows.Forms.Panel();
            this.systemEditorDisplayUpdater = new System.Windows.Forms.Timer();
            this.SuspendLayout();
            this.systemEditorMenuStrip.Location = new System.Drawing.Point(0, 0);
            this.systemEditorMenuStrip.Name = "systemEditorMenuStrip";
            this.systemEditorMenuStrip.Size = new System.Drawing.Size(1264, 24);
            this.systemEditorMenuStrip.TabIndex = 0;
            this.systemEditorMenuStrip.Text = "System Editor Menu Strip";
            this.systemEditorStatusStrip.Location = new System.Drawing.Point(0, 964);
            this.systemEditorStatusStrip.Name = "systemEditorStatusStrip";
            this.systemEditorStatusStrip.Size = new System.Drawing.Size(1264, 22);
            this.systemEditorStatusStrip.TabIndex = 1;
            this.systemEditorStatusStrip.Text = "System Editor Status Strip";
            this.systemEditorToolbarStrip.Location = new System.Drawing.Point(0, 24);
            this.systemEditorToolbarStrip.Name = "systemEditorToolbarStrip";
            this.systemEditorToolbarStrip.Size = new System.Drawing.Size(1264, 25);
            this.systemEditorToolbarStrip.TabIndex = 2;
            this.systemEditorToolbarStrip.Text = "System Editor Toolbar Strip";
            this.systemEditorDisplayPanel.Location = new System.Drawing.Point(12, 52);
            this.systemEditorDisplayPanel.Name = "systemEditorDisplayPanel";
            this.systemEditorDisplayPanel.Size = new System.Drawing.Size(640, 480);
            this.systemEditorDisplayPanel.BackColor = Color.Red;
            this.systemEditorDisplayUpdater.Interval = 20;
            this.systemEditorDisplayUpdater.Tick += new System.EventHandler(this.UpdateDisplay);
            this.systemEditorDisplayPanel.TabIndex = 3;
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(1264, 986);
            this.Controls.Add(this.systemEditorDisplayPanel);
            this.Controls.Add(this.systemEditorToolbarStrip);
            this.Controls.Add(this.systemEditorStatusStrip);
            this.Controls.Add(this.systemEditorMenuStrip);
            this.MainMenuStrip = this.systemEditorMenuStrip;
            this.Name = "systemEditorForm";
            this.Text = "System Editor";
            this.ResumeLayout(false);
            this.PerformLayout();
        }
        public SystemEditor()
        {
            InitializeComponent();
            sysEdDisp = new SystemEditorDisplay(this.systemEditorDisplayPanel.Handle);
            this.systemEditorDisplayUpdater.Enabled = true;
            this.systemEditorDisplayUpdater.Start();
        }
        private void UpdateDisplay(object sender,EventArgs e)
        {
            sysEdDisp.Tick();
        }
    }
}
This form is simply run from a static class with Aplication.Run(Form); Anybody have an ideas on why the panel is the red background color I set it at and not the Clear(Color.Green) it should be?

Share this post


Link to post
Share on other sites
Advertisement
How do you call a protected class?

Edit: From what I understood sysEdDisp.Tick(); did that for me...

Share this post


Link to post
Share on other sites
you need to make the class public?

I haven't tired to do this before with XNA, but have done the same thing with mdx, slimdx and OpenGL so I guess it wont be any different.

on the system editor form you could firstly override the onPaint function and then call SystemEditorDisplay.draw() and SystemEditorDisplay.update() in there.

but its better to add a new event handler to application.Idle() and then call SystemEditorDisplay.draw() and update from there. you need to remember that application.Idle is only called when the application goes idle and not while its idle so you need to set up some kind of way to make the application detect this and flag if it is still idle.. I found a good article on how to do this a while ago but cant seem to find it now.

just let me know if you need more info I could post some source.

Share this post


Link to post
Share on other sites
Maybe a little source would be nice, because I tried to implement something along the lines of what you said, and I still have a red panel :(
That is providing you have the time....

Share this post


Link to post
Share on other sites


public partial class EngineControl : UserControl
{
public EngineWrapper psEngine;

public EngineControl()
{
InitializeComponent();

if (!DesignMode)
{
psEngine = new EngineWrapper();

psEngine.init(this.Handle);


//add a new event handler which will be called every time the app goes idle
Application.Idle += main_loop;
}
}

protected override void WndProc(ref Message m)
{
if (!DesignMode)
{
psEngine.managed_window_proc((uint)m.Msg, (uint)m.WParam, (int)m.LParam);
}

base.WndProc(ref m);
}

public void main_loop(Object sender, EventArgs e)
{
//loop until the app becomes not idle
while (app_still_idle())
{
psEngine.render();
}
}

private bool app_still_idle()
{
//here we check if any windows messages have been recieved if not app is still idle
System.Windows.Forms.Message msg;
return !native_methods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0);
}

//native methods allow us to call peek message the same as a plain old win32 app
class native_methods
{
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern bool PeekMessage(out System.Windows.Forms.Message msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags);
}






essentially in that main loop function you want to do your draw and update calls. at the moment I think your just getting red background because you not actually invoking the draw function? ave you tried setting a break point in draw to see if it gets called?

Edit: also take note of !DesignMode in the constructor of EngineControl.. this is to prevent all your rendering code being created and called from inside windows forms designer... its nice that the forms designer executes your code in some situations, but it can lead to problems in the designer, and cause visual studio crashes, so I just disable it because I don't really care for viewing my rendered panel from inside visual studio.

Share this post


Link to post
Share on other sites
I've been giving this some thought actually, and I don't think I really need the XNA embedded, I'm wondering right now of having two seperate windows, one for graphical output, and a serperate one for the form, while embedded would be nice, and I really should chase it up for my own educational purposes, I'm not really writing production code here, just trying to make some tools to manipulate data, so I'm not really seeing any problem with this aproach either.

Thanx for your help and time, might just let you get back to what you were doing....

Share this post


Link to post
Share on other sites
I don't have time to look over your code right now, but have you looked at the sample on the creators club site that sticks XNA in a winform?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement