There's a lot of factors here that could effect what the best approach would be. Personally I would think about exactly what sort of control scheme I want from the form and design an interface for it, so for example:
public interface IControlSource
{
event KeyPressEventHandler KeyPress;
event MouseEventHandler MouseMove;
event MouseEventHandler MouseClick;
event EventHandler<ConsoleEventArgs> NewConsoleCommand;
}
This will allow me to handle key, and mouse input, and in this case console input (a simple text box on the form with a button that lets the user submit messages). I'm just using the KeyPress and MouseMove/MouseClick events already present on the Form class for simplicity. You could define your own specific events if you want, e.g. a MoveForward event.
The support class that will let me pass the console message to the game class:
public sealed class ConsoleEventArgs : EventArgs
{
#region Fields
private string commandLine;
#endregion
#region Methods
public ConsoleEventArgs(string commandLine)
{
this.commandLine = commandLine;
}
#endregion
#region Properties
public string CommandLine
{
get
{
return commandLine;
}
}
#endregion
}
For separation of concerns I'm also going to define a second interface called IRenderTarget, for rendering related features of the form:
public interface IRenderTarget
{
IntPtr GetDrawSurface();
event EventHandler VisibleChanged;
}
Now in our form we just need to implement these interfaces. The mouse and keyboard related events in IControlSource are already implemented by Form so lets implement the console event and IRenderTarget:
public partial class Form1 : Form, IControlSource, IRenderTarget
{
#region Fields
public event EventHandler<ConsoleEventArgs> NewConsoleCommand;
#endregion
#region Methods
public Form1()
{
InitializeComponent();
}
private void uiConsoleSubmit_Click(object sender, EventArgs e)
{
ConsoleEventArgs args = new ConsoleEventArgs(uiConsoleInput.Text);
uiConsoleInput.Text = string.Empty;
OnNewConsoleCommand(args);
}
protected virtual void OnNewConsoleCommand(ConsoleEventArgs e)
{
EventHandler<ConsoleEventArgs> handler = NewConsoleCommand;
if (handler != null)
handler(this, e);
}
public IntPtr GetRenderTarget()
{
return pctSurface.Handle;
}
#endregion
}
Now we can use dependency injection and pass these interfaces to the game class constructor, this will allow us to mock the form class should the need arise:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Form1 form = new Form1();
form.Show();
Game1 game = new Game1(form, form); //As Form1 implements both IRenderTarget and IControlSource
game.Run();
}
}
Finally the game class:
public class Game1
{
#region Fields
private IRenderTarget renderTarget;
private IControlSource controlSource;
#endregion
#region Methods
public Game1(IRenderTarget renderTarget, IControlSource controlSource)
{
this.renderTarget = renderTarget;
this.controlSource = controlSource;
this.drawSurface = renderTarget.GetDrawSurface();
renderTarget.VisibleChanged += new EventHandler(Game1_VisibleChanged);
controlSource.NewConsoleCommand += new EventHandler<ConsoleEventArgs>(controlSource_NewConsoleCommand);
//Can wire up other events too.
//...
}
private void controlSource_NewConsoleCommand(object sender, ConsoleEventArgs e)
{
string consoleMessage = e.CommandLine;
//Handle console input...
}
//...
#endregion
}
There's other ways you could approach this, such as reversing it and having the game class forward request to the form. You could take it further and add a state object shared between the form and game class via an interface. You could then handle all events within the form recording the input state to your state object. Within the game class you can then just query the state object (I believe this is closer to how input in XNA is normally handled?), allowing you to effectively remove these cross class events.
To be honest, I'm not overly fond of the approach to XNA in WinForms used in that blog post you linked - I think it may be prone to inducing messy code. Have you looked at the example at
http://creators.xna.com/en-GB/sample/winforms_series1?
Has this been any help or have I gone of on a tangent?
Go banana! | Super Nintendo Chalmers! | When I grow up I'm going to Bovine University!