Commits

Michael Gough committed dc2ad24

Integrated the foundation of a GUI/windowing system. After exploring and
experimenting with quite a few different approaches, the XNA game now runs
"hosted" within a WPF control within a WPF window. This gives the result I was
looking for of being able to build most of the game UI using WPF. This
subsequently allows me to learn WPF the fun way!

Comments (0)

Files changed (25)

WpfHostedXnaApplication/App.xaml

+<!--
+// App.xaml
+//
+// Copyright 2011, Nick Gravelyn.
+// Licensed under the terms of the Ms-PL: http://www.microsoft.com/opensource/licenses.mspx#Ms-PL
+-->
+    
+ <Application x:Class="WpfHostedXna.App"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             StartupUri="MainWindow.xaml">
+    <Application.Resources>
+         
+    </Application.Resources>
+</Application>

WpfHostedXnaApplication/App.xaml.cs

+#region File Description
+//-----------------------------------------------------------------------------
+// App.xaml.cs
+//
+// Copyright 2011, Nick Gravelyn.
+// Licensed under the terms of the Ms-PL: http://www.microsoft.com/opensource/licenses.mspx#Ms-PL
+//-----------------------------------------------------------------------------
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Windows;
+
+namespace WpfHostedXna
+{
+    /// <summary>
+    /// Interaction logic for App.xaml
+    /// </summary>
+    public partial class App : Application
+    {
+    }
+}

WpfHostedXnaApplication/Hosting Stuff/GraphicsDeviceControl.cs

+#region File Description
+//-----------------------------------------------------------------------------
+// NativeMethods.cs
+//
+// Copyright 2011, Nick Gravelyn.
+// Licensed under the terms of the Ms-PL: http://www.microsoft.com/opensource/licenses.mspx#Ms-PL
+//-----------------------------------------------------------------------------
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+using System.Windows;
+using System.Windows.Input;
+using System.Windows.Interop;
+using System.Windows.Media;
+using Microsoft.Xna.Framework.Graphics;
+using System.ComponentModel.Design;
+
+namespace WpfHostedXna
+{
+    /// <summary>
+    /// A control that enables XNA graphics rendering inside a WPF control through
+    /// the use of a hosted child Hwnd.
+    /// </summary>
+    public class GraphicsDeviceControl : HwndHost
+    {
+        #region Fields
+
+        public ServiceContainer Services
+        {
+
+          get { return services; }
+
+        }
+
+        ServiceContainer services = new ServiceContainer();
+
+        // The name of our window class
+        private const string windowClass = "GraphicsDeviceControlHostWindowClass";
+
+        // The HWND we present to when rendering
+        private IntPtr hWnd;
+
+        // For holding previous hWnd focus
+        private IntPtr hWndprev;
+
+        // The GraphicsDeviceService that provides and manages our GraphicsDevice
+        private GraphicsDeviceService graphicsService;
+
+        // Track if the application has focus
+        private bool applicationHasFocus = false;
+
+        // Track if the mouse is in the window
+        private bool mouseInWindow = false;
+
+        // Track the mouse state
+        private HwndMouseState mouseState = new HwndMouseState();
+
+        // Tracking whether we've "capture" the mouse
+        private bool isMouseCaptured = false;
+
+        // The screen coordinates of the mouse when captured
+        private int capturedMouseX;
+        private int capturedMouseY;
+
+        // The client coordinates of the mouse when captured
+        private int capturedMouseClientX;
+        private int capturedMouseClientY;
+
+        #endregion
+
+        #region Events
+
+        /// <summary>
+        /// Invoked when the control has initialized the GraphicsDevice.
+        /// </summary>
+        public event EventHandler<GraphicsDeviceEventArgs> LoadContent;
+
+        /// <summary>
+        /// Invoked when the control is ready to render XNA content
+        /// </summary>
+        public event EventHandler<GraphicsDeviceEventArgs> RenderXna;
+
+        /// <summary>
+        /// Invoked when the control receives a left mouse down message.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndLButtonDown;
+
+        /// <summary>
+        /// Invoked when the control receives a left mouse up message.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndLButtonUp;
+
+        /// <summary>
+        /// Invoked when the control receives a left mouse double click message.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndLButtonDblClick;
+
+        /// <summary>
+        /// Invoked when the control receives a right mouse down message.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndRButtonDown;
+
+        /// <summary>
+        /// Invoked when the control receives a right mouse up message.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndRButtonUp;
+
+        /// <summary>
+        /// Invoked when the control receives a rigt mouse double click message.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndRButtonDblClick;
+
+        /// <summary>
+        /// Invoked when the control receives a middle mouse down message.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndMButtonDown;
+
+        /// <summary>
+        /// Invoked when the control receives a middle mouse up message.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndMButtonUp;
+
+        /// <summary>
+        /// Invoked when the control receives a middle mouse double click message.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndMButtonDblClick;
+
+        /// <summary>
+        /// Invoked when the control receives a mouse down message for the first extra button.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndX1ButtonDown;
+
+        /// <summary>
+        /// Invoked when the control receives a mouse up message for the first extra button.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndX1ButtonUp;
+
+        /// <summary>
+        /// Invoked when the control receives a double click message for the first extra mouse button.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndX1ButtonDblClick;
+
+        /// <summary>
+        /// Invoked when the control receives a mouse down message for the second extra button.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndX2ButtonDown;
+
+        /// <summary>
+        /// Invoked when the control receives a mouse up message for the second extra button.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndX2ButtonUp;
+
+        /// <summary>
+        /// Invoked when the control receives a double click message for the first extra mouse button.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndX2ButtonDblClick;
+
+        /// <summary>
+        /// Invoked when the control receives a mouse move message.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndMouseMove;
+
+        /// <summary>
+        /// Invoked when the control first gets a mouse move message.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndMouseEnter;
+
+        /// <summary>
+        /// Invoked when the control gets a mouse leave message.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndMouseLeave;
+
+        /// <summary>
+        /// Invoked when the control recieves a mouse wheel delta.
+        /// </summary>
+        public event EventHandler<HwndMouseEventArgs> HwndMouseWheel;
+
+        #endregion
+
+        #region Construction and Disposal
+
+        public GraphicsDeviceControl()
+        {
+            // We must be notified of the control finishing loading so we can get the GraphicsDeviceService
+            Loaded += new System.Windows.RoutedEventHandler(XnaWindowHost_Loaded);
+
+            // We must be notified of the control changing sizes so we can resize the GraphicsDeviceService
+            SizeChanged += new SizeChangedEventHandler(XnaWindowHost_SizeChanged);
+
+            // We must be notified of the application foreground status for our mouse input events
+            Application.Current.Activated += new EventHandler(Current_Activated);
+            Application.Current.Deactivated += new EventHandler(Current_Deactivated);
+
+            // We use the CompositionTarget.Rendering event to trigger the control to draw itself
+            CompositionTarget.Rendering += CompositionTarget_Rendering;
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            // Release our reference to the GraphicsDeviceService if we have one
+            if (graphicsService != null)
+            {
+                graphicsService.Release(disposing);
+                graphicsService = null;
+            }
+
+            // Unhook the Rendering event so we no longer attempt to draw
+            CompositionTarget.Rendering -= CompositionTarget_Rendering;
+
+            base.Dispose(disposing);
+        }
+
+        #endregion
+
+        #region Public Methods
+
+        /// <summary>
+        /// Captures the mouse, hiding it and trapping it inside the window bounds.
+        /// </summary>
+        /// <remarks>
+        /// This method is useful for tooling scenarios where you only care about the mouse deltas
+        /// and want the user to be able to continue interacting with the window while they move
+        /// the mouse. A good example of this is rotating an object based on the mouse deltas where
+        /// through capturing you can spin and spin without having the cursor leave the window.
+        /// </remarks>
+        public new void CaptureMouse()
+        {
+            // Don't do anything if the mouse is already captured
+            if (isMouseCaptured)
+                return;
+
+            NativeMethods.ShowCursor(false);
+            isMouseCaptured = true;
+
+            // Store the current cursor position so we can reset the cursor back
+            // whenever we get a move message
+            NativeMethods.POINT p = new NativeMethods.POINT();
+            NativeMethods.GetCursorPos(ref p);
+            capturedMouseX = p.X;
+            capturedMouseY = p.Y;
+
+            // Get the client position of this point
+            NativeMethods.ScreenToClient(hWnd, ref p);
+            capturedMouseClientX = p.X;
+            capturedMouseClientY = p.Y;
+        }
+
+        /// <summary>
+        /// Releases the capture of the mouse which makes it visible and allows it to leave the window bounds.
+        /// </summary>
+        public new void ReleaseMouseCapture()
+        {
+            // Don't do anything if the mouse isn't captured
+            if (!isMouseCaptured)
+                return;
+
+            NativeMethods.ShowCursor(true);
+            isMouseCaptured = false;
+        }
+
+        #endregion
+
+        #region Graphics Device Control Implementation
+
+        void CompositionTarget_Rendering(object sender, EventArgs e)
+        {
+            // If we've captured the mouse, reset the cursor back to the captured position
+            if (isMouseCaptured &&
+                (int)mouseState.Position.X != capturedMouseX &&
+                (int)mouseState.Position.Y != capturedMouseY)
+            {
+                NativeMethods.SetCursorPos(capturedMouseX, capturedMouseY);
+
+                mouseState.Position = mouseState.PreviousPosition = new Point(capturedMouseClientX, capturedMouseClientY);
+            }
+
+            // If we have no graphics service, we can't draw
+            if (graphicsService == null)
+                return;
+
+            // Get the current width and height of the control
+            int width = (int)ActualWidth;
+            int height = (int)ActualHeight;
+
+            // If the control has no width or no height, skip drawing since it's not visible
+            if (width < 1 || height < 1)
+                return;
+
+            // Create the active viewport to which we'll render our content
+            Viewport viewport = new Viewport(0, 0, width, height);
+            graphicsService.GraphicsDevice.Viewport = viewport;
+
+            // Invoke the event to render this control
+            if (RenderXna != null)
+                RenderXna(this, new GraphicsDeviceEventArgs(graphicsService.GraphicsDevice));
+
+            // Present to the screen, but only use the visible area of the back buffer
+            graphicsService.GraphicsDevice.Present(viewport.Bounds, null, hWnd);
+        }
+
+        void XnaWindowHost_Loaded(object sender, RoutedEventArgs e)
+        {
+            // If we don't yet have a GraphicsDeviceService reference, we must add one for this control
+            if (graphicsService == null)
+            {
+                graphicsService = GraphicsDeviceService.AddRef(hWnd, (int)ActualWidth, (int)ActualHeight);
+
+                services.AddService( typeof(IGraphicsDeviceService), graphicsService );
+
+                // Invoke the LoadContent event
+                if (LoadContent != null)
+                    LoadContent(this, new GraphicsDeviceEventArgs(graphicsService.GraphicsDevice));
+            }
+        }
+
+        void XnaWindowHost_SizeChanged(object sender, SizeChangedEventArgs e)
+        {
+            // If we have a reference to the GraphicsDeviceService, we must reset it based on our updated size
+            if (graphicsService != null)
+                graphicsService.ResetDevice((int)ActualWidth, (int)ActualHeight);
+        }
+
+        void Current_Activated(object sender, EventArgs e)
+        {
+            applicationHasFocus = true;
+        }
+
+        void Current_Deactivated(object sender, EventArgs e)
+        {
+            applicationHasFocus = false;
+            ResetMouseState();
+
+            if (mouseInWindow)
+            {
+                mouseInWindow = false;
+                if (HwndMouseLeave != null)
+                    HwndMouseLeave(this, new HwndMouseEventArgs(mouseState));
+            }
+
+            ReleaseMouseCapture();
+        }
+
+        private void ResetMouseState()
+        {
+            // We need to invoke events for any buttons that were pressed
+            bool fireL = mouseState.LeftButton == MouseButtonState.Pressed;
+            bool fireM = mouseState.MiddleButton == MouseButtonState.Pressed;
+            bool fireR = mouseState.RightButton == MouseButtonState.Pressed;
+            bool fireX1 = mouseState.X1Button == MouseButtonState.Pressed;
+            bool fireX2 = mouseState.X2Button == MouseButtonState.Pressed;
+
+            // Update the state of all of the buttons
+            mouseState.LeftButton = MouseButtonState.Released;
+            mouseState.MiddleButton = MouseButtonState.Released;
+            mouseState.RightButton = MouseButtonState.Released;
+            mouseState.X1Button = MouseButtonState.Released;
+            mouseState.X2Button = MouseButtonState.Released;
+
+            // Fire any events
+            HwndMouseEventArgs args = new HwndMouseEventArgs(mouseState);
+            if (fireL && HwndLButtonUp != null)
+                HwndLButtonUp(this, args);
+            if (fireM && HwndMButtonUp != null)
+                HwndMButtonUp(this, args);
+            if (fireR && HwndRButtonUp != null)
+                HwndRButtonUp(this, args);
+            if (fireX1 && HwndX1ButtonUp != null)
+                HwndX1ButtonUp(this, args);
+            if (fireX2 && HwndX2ButtonUp != null)
+                HwndX2ButtonUp(this, args);
+            // The mouse is no longer considered to be in our window
+            mouseInWindow = false;
+        }
+
+        #endregion
+
+        #region HWND Management
+
+        protected override HandleRef BuildWindowCore(HandleRef hwndParent)
+        {
+            // Create the host window as a child of the parent
+            hWnd = CreateHostWindow(hwndParent.Handle);
+            return new HandleRef(this, hWnd);
+        }
+
+        protected override void DestroyWindowCore(HandleRef hwnd)
+        {
+            // Destroy the window and reset our hWnd value
+            NativeMethods.DestroyWindow(hwnd.Handle);
+            hWnd = IntPtr.Zero;
+        }
+
+        /// <summary>
+        /// Creates the host window as a child of the parent window.
+        /// </summary>
+        private IntPtr CreateHostWindow(IntPtr hWndParent)
+        {
+            // Register our window class
+            RegisterWindowClass();
+
+            // Create the window
+            return NativeMethods.CreateWindowEx(0, windowClass, "",
+               NativeMethods.WS_CHILD | NativeMethods.WS_VISIBLE,
+               0, 0, (int)Width, (int)Height, hWndParent, IntPtr.Zero, IntPtr.Zero, 0);
+        }
+
+        /// <summary>
+        /// Registers the window class.
+        /// </summary>
+        private void RegisterWindowClass()
+        {
+            NativeMethods.WNDCLASSEX wndClass = new NativeMethods.WNDCLASSEX();
+            wndClass.cbSize = (uint)Marshal.SizeOf(wndClass);
+            wndClass.hInstance = NativeMethods.GetModuleHandle(null);
+            wndClass.lpfnWndProc = NativeMethods.DefaultWindowProc;
+            wndClass.lpszClassName = windowClass;
+            wndClass.hCursor = NativeMethods.LoadCursor(IntPtr.Zero, NativeMethods.IDC_ARROW);
+
+            NativeMethods.RegisterClassEx(ref wndClass);
+        }
+
+        #endregion
+
+        #region WndProc Implementation
+
+        protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
+        {
+            switch (msg)
+            {
+                case NativeMethods.WM_MOUSEWHEEL:
+                    if (mouseInWindow)
+                    {
+                        int delta = wParam.ToInt32();
+                        if (HwndMouseWheel != null)
+                            HwndMouseWheel(this, new HwndMouseEventArgs(mouseState, delta, 0));
+                    }
+                    break;
+                case NativeMethods.WM_LBUTTONDOWN:
+                    mouseState.LeftButton = MouseButtonState.Pressed;
+                    if (HwndLButtonDown != null)
+                        HwndLButtonDown(this, new HwndMouseEventArgs(mouseState));
+                    break;
+                case NativeMethods.WM_LBUTTONUP:
+                    mouseState.LeftButton = MouseButtonState.Released;
+                    if (HwndLButtonUp != null)
+                        HwndLButtonUp(this, new HwndMouseEventArgs(mouseState));
+                    break;
+                case NativeMethods.WM_LBUTTONDBLCLK:
+                    if (HwndLButtonDblClick != null)
+                        HwndLButtonDblClick(this, new HwndMouseEventArgs(mouseState, MouseButton.Left));
+                    break;
+                case NativeMethods.WM_RBUTTONDOWN:
+                    mouseState.RightButton = MouseButtonState.Pressed;
+                    if (HwndRButtonDown != null)
+                        HwndRButtonDown(this, new HwndMouseEventArgs(mouseState));
+                    break;
+                case NativeMethods.WM_RBUTTONUP:
+                    mouseState.RightButton = MouseButtonState.Released;
+                    if (HwndRButtonUp != null)
+                        HwndRButtonUp(this, new HwndMouseEventArgs(mouseState));
+                    break;
+                case NativeMethods.WM_RBUTTONDBLCLK:
+                    if (HwndRButtonDblClick != null)
+                        HwndRButtonDblClick(this, new HwndMouseEventArgs(mouseState, MouseButton.Right));
+                    break;
+                case NativeMethods.WM_MBUTTONDOWN:
+                    mouseState.MiddleButton = MouseButtonState.Pressed;
+                    if (HwndMButtonDown != null)
+                        HwndMButtonDown(this, new HwndMouseEventArgs(mouseState));
+                    break;
+                case NativeMethods.WM_MBUTTONUP:
+                    mouseState.MiddleButton = MouseButtonState.Released;
+                    if (HwndMButtonUp != null)
+                        HwndMButtonUp(this, new HwndMouseEventArgs(mouseState));
+                    break;
+                case NativeMethods.WM_MBUTTONDBLCLK:
+                    if (HwndMButtonDblClick != null)
+                        HwndMButtonDblClick(this, new HwndMouseEventArgs(mouseState, MouseButton.Middle));
+                    break;
+                case NativeMethods.WM_XBUTTONDOWN:
+                    if (((int)wParam & NativeMethods.MK_XBUTTON1) != 0)
+                    {
+                        mouseState.X1Button = MouseButtonState.Pressed;
+                        if (HwndX1ButtonDown != null)
+                            HwndX1ButtonDown(this, new HwndMouseEventArgs(mouseState));
+                    }
+                    else if (((int)wParam & NativeMethods.MK_XBUTTON2) != 0)
+                    {
+                        mouseState.X2Button = MouseButtonState.Pressed;
+                        if (HwndX2ButtonDown != null)
+                            HwndX2ButtonDown(this, new HwndMouseEventArgs(mouseState));
+                    }
+                    break;
+                case NativeMethods.WM_XBUTTONUP:
+                    if (((int)wParam & NativeMethods.MK_XBUTTON1) != 0)
+                    {
+                        mouseState.X1Button = MouseButtonState.Released;
+                        if (HwndX1ButtonUp != null)
+                            HwndX1ButtonUp(this, new HwndMouseEventArgs(mouseState));
+                    }
+                    else if (((int)wParam & NativeMethods.MK_XBUTTON2) != 0)
+                    {
+                        mouseState.X2Button = MouseButtonState.Released;
+                        if (HwndX2ButtonUp != null)
+                            HwndX2ButtonUp(this, new HwndMouseEventArgs(mouseState));
+                    }
+                    break;
+                case NativeMethods.WM_XBUTTONDBLCLK:
+                    if (((int)wParam & NativeMethods.MK_XBUTTON1) != 0)
+                    {
+                        if (HwndX1ButtonDblClick != null)
+                            HwndX1ButtonDblClick(this, new HwndMouseEventArgs(mouseState, MouseButton.XButton1));
+                    }
+                    else if (((int)wParam & NativeMethods.MK_XBUTTON2) != 0)
+                    {
+                        if (HwndX2ButtonDblClick != null)
+                            HwndX2ButtonDblClick(this, new HwndMouseEventArgs(mouseState, MouseButton.XButton2));
+                    }
+                    break;
+                case NativeMethods.WM_MOUSEMOVE:
+                    // If the application isn't in focus, we don't handle this message
+                    if (!applicationHasFocus)
+                        break;
+
+                    // record the prevous and new position of the mouse
+                    mouseState.PreviousPosition = mouseState.Position;
+                    mouseState.Position = new Point(
+                        NativeMethods.GetXLParam((int)lParam),
+                        NativeMethods.GetYLParam((int)lParam));
+
+                    if (!mouseInWindow)
+                    {
+                        mouseInWindow = true;
+
+                        // if the mouse is just entering, use the same position for the previous state
+                        // so we don't get weird deltas happening when the move event fires
+                        mouseState.PreviousPosition = mouseState.Position;
+
+                        if (HwndMouseEnter != null)
+                            HwndMouseEnter(this, new HwndMouseEventArgs(mouseState));
+
+                        hWndprev = NativeMethods.GetFocus();
+                        NativeMethods.SetFocus( hWnd );
+
+                        // send the track mouse event so that we get the WM_MOUSELEAVE message
+                        NativeMethods.TRACKMOUSEEVENT tme = new NativeMethods.TRACKMOUSEEVENT();
+                        tme.cbSize = Marshal.SizeOf(typeof(NativeMethods.TRACKMOUSEEVENT));
+                        tme.dwFlags = NativeMethods.TME_LEAVE;
+                        tme.hWnd = hwnd;
+                        NativeMethods.TrackMouseEvent(ref tme);
+                    }
+
+                    // Only fire the mouse move if the position actually changed
+                    if (mouseState.Position != mouseState.PreviousPosition)
+                    {
+                        if (HwndMouseMove != null)
+                            HwndMouseMove(this, new HwndMouseEventArgs(mouseState));
+                    }
+
+                    break;
+                case NativeMethods.WM_MOUSELEAVE:
+
+                    // If we have capture, we ignore this message because we're just
+                    // going to reset the cursor position back into the window
+                    if (isMouseCaptured)
+                        break;
+
+                    // Reset the state which releases all buttons and 
+                    // marks the mouse as not being in the window.
+                    ResetMouseState();
+
+                    if (HwndMouseLeave != null)
+                        HwndMouseLeave(this, new HwndMouseEventArgs(mouseState));
+
+                    NativeMethods.SetFocus( hWndprev );
+                    break;
+                default:
+                    break;
+            }
+
+            return base.WndProc(hwnd, msg, wParam, lParam, ref handled);
+        }
+
+        #endregion
+    }
+}

WpfHostedXnaApplication/Hosting Stuff/GraphicsDeviceEventArgs.cs

+#region File Description
+//-----------------------------------------------------------------------------
+// GraphicsDeviceEventArgs.cs
+//
+// Copyright 2011, Nick Gravelyn.
+// Licensed under the terms of the Ms-PL: http://www.microsoft.com/opensource/licenses.mspx#Ms-PL
+//-----------------------------------------------------------------------------
+#endregion
+
+using System;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace WpfHostedXna
+{
+    /// <summary>
+    /// Arguments used for GraphicsDevice related events.
+    /// </summary>
+    public class GraphicsDeviceEventArgs : EventArgs
+    {
+        /// <summary>
+        /// Gets the GraphicsDevice.
+        /// </summary>
+        public GraphicsDevice GraphicsDevice { get; private set; }
+
+        /// <summary>
+        /// Initializes a new GraphicsDeviceEventArgs.
+        /// </summary>
+        /// <param name="device">The GraphicsDevice associated with the event.</param>
+        public GraphicsDeviceEventArgs(GraphicsDevice device)
+        {
+            GraphicsDevice = device;
+        }
+    }
+}

WpfHostedXnaApplication/Hosting Stuff/GraphicsDeviceService.cs

+#region File Description
+//-----------------------------------------------------------------------------
+// GraphicsDeviceService.cs
+//
+// Copyright 2011, Nick Gravelyn.
+// Licensed under the terms of the Ms-PL: http://www.microsoft.com/opensource/licenses.mspx#Ms-PL
+//-----------------------------------------------------------------------------
+#endregion
+
+using System;
+using System.Threading;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace WpfHostedXna
+{
+    /// <summary>
+    /// Helper class responsible for creating and managing the GraphicsDevice.
+    /// All GraphicsDeviceControl instances share the same GraphicsDeviceService,
+    /// so even though there can be many controls, there will only ever be a single
+    /// underlying GraphicsDevice. This implements the standard IGraphicsDeviceService
+    /// interface, which provides notification events for when the device is reset
+    /// or disposed.
+    /// </summary>
+    class GraphicsDeviceService : IGraphicsDeviceService
+    {
+        // Singleton device service instance.
+        private static readonly GraphicsDeviceService singletonInstance = new GraphicsDeviceService();
+
+        // Keep track of how many controls are sharing the singletonInstance.
+        private static int referenceCount;
+
+        private GraphicsDevice graphicsDevice;
+
+        // Store the current device settings.
+        private PresentationParameters parameters;
+
+        /// <summary>
+        /// Gets the current graphics device.
+        /// </summary>
+        public GraphicsDevice GraphicsDevice
+        {
+            get { return graphicsDevice; }
+        }
+
+
+        // IGraphicsDeviceService events.
+        public event EventHandler<EventArgs> DeviceCreated;
+        public event EventHandler<EventArgs> DeviceDisposing;
+        public event EventHandler<EventArgs> DeviceReset;
+        public event EventHandler<EventArgs> DeviceResetting;
+
+        /// <summary>
+        /// Constructor is private, because this is a singleton class:
+        /// client controls should use the public AddRef method instead.
+        /// </summary>
+        private GraphicsDeviceService() { }
+
+        private void CreateDevice(IntPtr windowHandle, int width, int height)
+        {
+            parameters = new PresentationParameters();
+
+            parameters.BackBufferWidth = Math.Max(width, 1);
+            parameters.BackBufferHeight = Math.Max(height, 1);
+            parameters.BackBufferFormat = SurfaceFormat.Color;
+            parameters.DepthStencilFormat = DepthFormat.Depth24;
+            parameters.DeviceWindowHandle = windowHandle;
+            parameters.PresentationInterval = PresentInterval.Immediate;
+            parameters.IsFullScreen = false;
+
+            graphicsDevice = new GraphicsDevice(
+                GraphicsAdapter.DefaultAdapter,
+                GraphicsProfile.Reach,
+                parameters);
+
+            if (DeviceCreated != null)
+                DeviceCreated(this, EventArgs.Empty);
+        }
+
+
+        /// <summary>
+        /// Gets a reference to the singleton instance.
+        /// </summary>
+        public static GraphicsDeviceService AddRef(IntPtr windowHandle, int width, int height)
+        {
+            // Increment the "how many controls sharing the device" reference count.
+            if (Interlocked.Increment(ref referenceCount) == 1)
+            {
+                // If this is the first control to start using the
+                // device, we must create the device.
+                singletonInstance.CreateDevice(windowHandle, width, height);
+            }
+
+            return singletonInstance;
+        }
+
+
+        /// <summary>
+        /// Releases a reference to the singleton instance.
+        /// </summary>
+        public void Release(bool disposing)
+        {
+            // Decrement the "how many controls sharing the device" reference count.
+            if (Interlocked.Decrement(ref referenceCount) == 0)
+            {
+                // If this is the last control to finish using the
+                // device, we should dispose the singleton instance.
+                if (disposing)
+                {
+                    if (DeviceDisposing != null)
+                        DeviceDisposing(this, EventArgs.Empty);
+
+                    graphicsDevice.Dispose();
+                }
+
+                graphicsDevice = null;
+            }
+        }
+
+        
+        /// <summary>
+        /// Resets the graphics device to whichever is bigger out of the specified
+        /// resolution or its current size. This behavior means the device will
+        /// demand-grow to the largest of all its GraphicsDeviceControl clients.
+        /// </summary>
+        public void ResetDevice(int width, int height)
+        {
+            if (DeviceResetting != null)
+                DeviceResetting(this, EventArgs.Empty);
+
+            parameters.BackBufferWidth = Math.Max(parameters.BackBufferWidth, width);
+            parameters.BackBufferHeight = Math.Max(parameters.BackBufferHeight, height);
+
+            graphicsDevice.Reset(parameters);
+
+            if (DeviceReset != null)
+                DeviceReset(this, EventArgs.Empty);
+        }
+    }
+}

WpfHostedXnaApplication/Hosting Stuff/HwndMouseEventArgs.cs

+#region File Description
+//-----------------------------------------------------------------------------
+// HwndMouseEventArgs.cs
+//
+// Copyright 2011, Nick Gravelyn.
+// Licensed under the terms of the Ms-PL: http://www.microsoft.com/opensource/licenses.mspx#Ms-PL
+//-----------------------------------------------------------------------------
+#endregion
+
+using System;
+using System.Windows.Input;
+using System.Windows;
+
+namespace WpfHostedXna
+{
+    /// <summary>
+    /// Event arguments used for mouse events in the GraphicsDeviceControl.
+    /// </summary>
+    public class HwndMouseEventArgs : EventArgs
+    {
+        /// <summary>
+        /// Gets the state of the left mouse button.
+        /// </summary>
+        public MouseButtonState LeftButton { get; private set; }
+
+        /// <summary>
+        /// Gets the state of the right mouse button.
+        /// </summary>
+        public MouseButtonState RightButton { get; private set; }
+
+        /// <summary>
+        /// Gets the state of the middle mouse button.
+        /// </summary>
+        public MouseButtonState MiddleButton { get; private set; }
+
+        /// <summary>
+        /// Gets the state of the first extra mouse button.
+        /// </summary>
+        public MouseButtonState X1Button { get; private set; }
+
+        /// <summary>
+        /// Gets the state of the second extra mouse button.
+        /// </summary>
+        public MouseButtonState X2Button { get; private set; }
+
+        /// <summary>
+        /// Gets the button that was double clicked.
+        /// </summary>
+        public MouseButton? DoubleClickButton { get; private set; }
+
+        /// <summary>
+        /// Gets the mouse wheel delta.
+        /// </summary>
+        public int WheelDelta { get; private set; }
+
+        /// <summary>
+        /// Gets the horizontal mouse wheel delta.
+        /// </summary>
+        public int HorizontalWheelDelta { get; private set; }
+
+        /// <summary>
+        /// Gets the current position of the mouse.
+        /// </summary>
+        public Point Position { get; private set; }
+
+        /// <summary>
+        /// Gets the previous position of the mouse.
+        /// </summary>
+        public Point PreviousPosition { get; private set; }
+
+        /// <summary>
+        /// Initializes a new HwndMouseEventArgs.
+        /// </summary>
+        /// <param name="state">The state from which to initialize the properties.</param>
+        public HwndMouseEventArgs(HwndMouseState state)
+        {
+            LeftButton = state.LeftButton;
+            RightButton = state.RightButton;
+            MiddleButton = state.MiddleButton;
+            X1Button = state.X1Button;
+            X2Button = state.X2Button;
+            Position = state.Position;
+            PreviousPosition = state.PreviousPosition;
+        }
+
+        /// <summary>
+        /// Initializes a new HwndMouseEventArgs.
+        /// </summary>
+        /// <param name="state">The state from which to initialize the properties.</param>
+        /// <param name="mouseWheelDelta">The mouse wheel rotation delta.</param>
+        public HwndMouseEventArgs(HwndMouseState state, int mouseWheelDelta, int mouseHWheelDelta)
+            : this(state)
+        {
+            WheelDelta = mouseWheelDelta;
+            HorizontalWheelDelta = mouseHWheelDelta;
+        }
+        
+        /// <summary>
+        /// Initializes a new HwndMouseEventArgs.
+        /// </summary>
+        /// <param name="state">The state from which to initialize the properties.</param>
+        /// <param name="doubleClickButton">The button that was double clicked.</param>
+        public HwndMouseEventArgs(HwndMouseState state, MouseButton doubleClickButton)
+            : this(state)
+        {
+            DoubleClickButton = doubleClickButton;
+        }
+    }
+}

WpfHostedXnaApplication/Hosting Stuff/HwndMouseState.cs

+#region File Description
+//-----------------------------------------------------------------------------
+// HwndMouseState.cs
+//
+// Copyright 2011, Nick Gravelyn.
+// Licensed under the terms of the Ms-PL: http://www.microsoft.com/opensource/licenses.mspx#Ms-PL
+//-----------------------------------------------------------------------------
+#endregion
+
+using System.Windows;
+using System.Windows.Input;
+
+namespace WpfHostedXna
+{
+    /// <summary>
+    /// Represents the state of a mouse. Used by the GraphicsDeviceControl to track mouse state
+    /// and for constructing the HwndMouseEventArgs.
+    /// </summary>
+    public class HwndMouseState
+    {
+        /// <summary>
+        /// The current state of the left mouse button.
+        /// </summary>
+        public MouseButtonState LeftButton;
+
+        /// <summary>
+        /// The current state of the right mouse button.
+        /// </summary>
+        public MouseButtonState RightButton;
+
+        /// <summary>
+        /// The current state of the middle mouse button.
+        /// </summary>
+        public MouseButtonState MiddleButton;
+
+        /// <summary>
+        /// The current state of the first extra mouse button.
+        /// </summary>
+        public MouseButtonState X1Button;
+
+        /// <summary>
+        /// The current state of the second extra mouse button.
+        /// </summary>
+        public MouseButtonState X2Button;
+        
+        /// <summary>
+        /// The current position of the mouse.
+        /// </summary>
+        public Point Position;
+
+        /// <summary>
+        /// The previous position of the mouse.
+        /// </summary>
+        public Point PreviousPosition;
+    }
+}

WpfHostedXnaApplication/Hosting Stuff/NativeMethods.cs

+#region File Description
+//-----------------------------------------------------------------------------
+// NativeMethods.cs
+//
+// Copyright 2011, Nick Gravelyn.
+// Licensed under the terms of the Ms-PL: http://www.microsoft.com/opensource/licenses.mspx#Ms-PL
+//-----------------------------------------------------------------------------
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace WpfHostedXna
+{
+    /// <summary>
+    /// An internal set of functionality used for interopping with native Win32 APIs.
+    /// </summary>
+    internal static class NativeMethods
+    {
+        #region Constants
+
+        // Define the window styles we use
+        public const int WS_CHILD = 0x40000000;
+        public const int WS_VISIBLE = 0x10000000;
+
+        // Define the Windows messages we will handle
+        public const int WM_MOUSEMOVE = 0x0200;
+        public const int WM_LBUTTONDOWN = 0x0201;
+        public const int WM_LBUTTONUP = 0x0202;
+        public const int WM_LBUTTONDBLCLK = 0x0203;
+        public const int WM_RBUTTONDOWN = 0x0204;
+        public const int WM_RBUTTONUP = 0x0205;
+        public const int WM_RBUTTONDBLCLK = 0x0206;
+        public const int WM_MBUTTONDOWN = 0x0207;
+        public const int WM_MBUTTONUP = 0x0208;
+        public const int WM_MBUTTONDBLCLK = 0x0209;
+        public const int WM_MOUSEWHEEL = 0x020A;
+        public const int WM_XBUTTONDOWN = 0x020B;
+        public const int WM_XBUTTONUP = 0x020C;
+        public const int WM_XBUTTONDBLCLK = 0x020D;
+        public const int WM_MOUSELEAVE = 0x02A3;
+
+        // Define the values that let us differentiate between the two extra mouse buttons
+        public const int MK_XBUTTON1 = 0x020;
+        public const int MK_XBUTTON2 = 0x040;
+
+        // Define the cursor icons we use
+        public const int IDC_ARROW = 32512;
+
+        // Define the TME_LEAVE value so we can register for WM_MOUSELEAVE messages
+        public const uint TME_LEAVE = 0x00000002;
+
+        #endregion
+
+        #region Delegates and Structs
+
+        public delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
+
+        public static readonly WndProc DefaultWindowProc = DefWindowProc;
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct TRACKMOUSEEVENT
+        {
+            public int cbSize;
+            public uint dwFlags;
+            public IntPtr hWnd;
+            public uint dwHoverTime;
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct WNDCLASSEX
+        {
+            public uint cbSize;
+            public uint style;
+            [MarshalAs(UnmanagedType.FunctionPtr)]
+            public WndProc lpfnWndProc;
+            public int cbClsExtra;
+            public int cbWndExtra;
+            public IntPtr hInstance;
+            public IntPtr hIcon;
+            public IntPtr hCursor;
+            public IntPtr hbrBackground;
+            public string lpszMenuName;
+            public string lpszClassName;
+            public IntPtr hIconSm;
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct POINT
+        {
+            public int X;
+            public int Y;
+        }
+
+        #endregion
+
+        #region DllImports
+
+        [DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Auto)]
+        public static extern IntPtr CreateWindowEx(
+            int exStyle,
+            string className,
+            string windowName,
+            int style,
+            int x, int y,
+            int width, int height,
+            IntPtr hwndParent,
+            IntPtr hMenu,
+            IntPtr hInstance,
+            [MarshalAs(UnmanagedType.AsAny)] object pvParam);
+
+        [DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Auto)]
+        public static extern bool DestroyWindow(IntPtr hwnd);
+
+        [DllImport("user32.dll")]
+        public static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
+
+        [DllImport("kernel32.dll")]
+        public static extern IntPtr GetModuleHandle(string module);
+
+        [DllImport("user32.dll")]
+        public static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);
+
+        [DllImport("user32.dll")]
+        public static extern int TrackMouseEvent(ref TRACKMOUSEEVENT lpEventTrack);
+
+        [DllImport("user32.dll")]
+        [return: MarshalAs(UnmanagedType.U2)]
+        public static extern short RegisterClassEx([In] ref WNDCLASSEX lpwcx);
+
+        [DllImport("user32.dll")]
+        public static extern int ShowCursor(bool bShow);
+
+        [DllImport("user32.dll")]
+        public static extern bool GetCursorPos(ref POINT point);
+
+        [DllImport("user32.dll")]
+        public static extern bool SetCursorPos(int x, int y);
+
+        [DllImport("user32.dll")]
+        public static extern int ScreenToClient(IntPtr hWnd, ref POINT pt);
+
+        [DllImport("user32.dll")]
+        public static extern int SetFocus(IntPtr hWnd);
+
+        [DllImport("user32.dll")]
+        public static extern IntPtr GetFocus();
+
+        #endregion
+
+        #region Helpers
+        
+        public static int GetXLParam(int lParam) 
+        {
+            return LowWord(lParam);
+        }
+
+        public static int GetYLParam(int lParam) 
+        {
+            return HighWord(lParam);
+        }
+
+        public static int LowWord(int input)
+        {
+            return (int)(input & 0xffff);
+        }
+
+        public static int HighWord(int input)
+        {
+            return (int)(input >> 16);
+        }
+
+        #endregion
+    }
+}

WpfHostedXnaApplication/MVVM Helpers/DelegateCommand.cs

+namespace Mvvm
+{
+    using System;
+    using System.Diagnostics;
+    using System.Windows.Input;
+
+    public class DelegateCommand : ICommand
+    {
+        private readonly Action<object> _execute;
+        private readonly Predicate<object> _canExecute;
+
+        #region Constructors
+
+        public DelegateCommand(Action<object> execute, Predicate<object> canExecute = null)
+        {
+            if (execute == null)
+                throw new ArgumentNullException("execute");
+
+            _execute = execute;
+            _canExecute = canExecute;
+        }
+        #endregion
+
+        #region ICommand Members
+
+        [DebuggerStepThrough]
+        public bool CanExecute(object parameter)
+        {
+            return _canExecute == null ? true : _canExecute(parameter);
+        }
+
+        public event EventHandler CanExecuteChanged
+        {
+            add { CommandManager.RequerySuggested += value; }
+            remove { CommandManager.RequerySuggested -= value; }
+        }
+
+        public void Execute(object parameter)
+        {
+            _execute(parameter);
+        }
+
+        #endregion
+    }
+}

WpfHostedXnaApplication/MVVM Helpers/PropertyChanged.cs

+namespace Mvvm
+{
+    using System;
+    using System.ComponentModel;
+    using System.Linq.Expressions;
+
+    /// <summary>
+    /// Generic extension methods used by the framework.
+    /// </summary>
+    public static class PropertyChangedExtensionMethods
+    {
+        /// <summary>
+        /// Raises the PropertyChanged event.
+        /// </summary>
+        public static void Raise<T, P>(this PropertyChangedEventHandler pc, T source, Expression<Func<T, P>> pe)
+        {
+            if (pc != null)
+            {
+                pc.Invoke(source,
+                    new PropertyChangedEventArgs(((MemberExpression)pe.Body).Member.Name));
+            }
+        }
+
+        /// <summary>
+        /// Raises the PropertyChanged event for all properties.
+        /// </summary>
+        public static void RaiseAll<T>(this PropertyChangedEventHandler pc, T source)
+        {
+            if (pc != null)
+            {
+                pc.Invoke(source, new PropertyChangedEventArgs(string.Empty));
+            }
+        }
+    }
+}

WpfHostedXnaApplication/MainWindow.xaml

+<!--
+// MainWindow.xaml
+//
+// Copyright 2011, Nick Gravelyn.
+// Licensed under the terms of the Ms-PL: http://www.microsoft.com/opensource/licenses.mspx#Ms-PL
+-->
+    
+ <Window x:Class="WpfHostedXna.MainWindow"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:my="clr-namespace:WpfHostedXna"
+        xmlns:ctrl="clr-namespace:System.Windows.Controls"
+                 Title="MainWindow" Height="480" Width="800">
+                  <!--WindowStyle="None"
+                  AllowsTransparency="true"
+                  Background="Transparent"-->
+
+    <Grid>
+
+        <!--<Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="*" />
+        </Grid.RowDefinitions>-->
+        
+        <!-- Add a placeholder menu to show that you can build great UI around your XNA rendered content -->
+        <!--<Menu Grid.Row="0">
+            <MenuItem Header="_File">
+                <MenuItem Header="_New" />
+                <MenuItem Header="_Open" />
+                <MenuItem Header="_Save" />
+                <MenuItem Header="Save _As" />
+                <MenuItem Header="E_xit" />
+            </MenuItem>
+            <MenuItem Header="_Edit" />
+            <MenuItem Header="_Window" />
+            <MenuItem Header="_Help" />
+        </Menu>-->
+        
+        <!--<Grid Grid.Row="1">-->
+            
+            <!--<Grid.ColumnDefinitions>
+                <ColumnDefinition Width="150" />
+                <ColumnDefinition Width="*" />
+            </Grid.ColumnDefinitions>
+            
+            <Grid.RowDefinitions>
+                <RowDefinition Height="*" />
+                <RowDefinition Height="5" />
+                <RowDefinition Height="*" />
+            </Grid.RowDefinitions>-->
+            
+            <!-- We use a StackPanel to easily lay out some sliders to adjust a color. -->
+            <!--<StackPanel Grid.Column="0" Grid.Row="0" Margin="5">
+                <TextBlock Text="R Component" />
+                <Slider x:Name="rComponent" Minimum="0" Maximum="1" SmallChange="0.01" LargeChange="0.1" Value="1" />
+
+                <TextBlock Text="G Component" />
+                <Slider x:Name="gComponent" Minimum="0" Maximum="1" SmallChange="0.01" LargeChange="0.1" Value="0" />
+
+                <TextBlock Text="B Component" />
+                <Slider x:Name="bComponent" Minimum="0" Maximum="1" SmallChange="0.01" LargeChange="0.1" Value="0" />
+            </StackPanel>
+            
+            <StackPanel Grid.Column="0" Grid.Row="3">
+                <Button x:Name="redButton" Content="_Red (R)" Margin="5" Click="redButton_Click" />
+                <Button x:Name="greenButton" Content="_Green (G)" Margin="5" Click="greenButton_Click" />
+                <Button x:Name="blueButton" Content="_Blue (B)" Margin="5" Click="blueButton_Click" />
+            </StackPanel>-->
+
+            <!-- We can add multiple GraphicsDeviceControls for rendering with the XNA Framework. -->
+            <!--<my:GraphicsDeviceControl x:Name="xnaControl1" Grid.Column="1" Grid.Row="0"
+                                      LoadContent="loadContent"
+                                      RenderXna="xnaControl1_RenderXna" />-->
+        <!--<Border BorderThickness="3"
+                BorderBrush="DarkGray"
+                Opacity="0.5"
+                CornerRadius="6">
+            <DockPanel>-->
+                <!--<Grid Background="Black" Opacity="0.3">-->
+                    <my:GraphicsDeviceControl x:Name="xnaControl2" 
+                                      LoadContent="loadContent"
+                                      RenderXna="xnaControl2_RenderXna" 
+                                      HwndMouseMove="xnaControl2_MouseMove"
+                                      HwndLButtonDown="xnaControl2_HwndLButtonDown"
+                                      HwndLButtonUp="xnaControl2_HwndLButtonUp"
+                                      HwndMouseWheel="xnaControl2_HwndMouseWheel"/>
+                    
+                <!--</Grid>
+                    
+
+
+                
+             </DockPanel>
+        </Border>-->
+        <!--</Grid>-->
+        
+    </Grid>
+</Window>

WpfHostedXnaApplication/MainWindow.xaml.cs

+#region File Description
+//-----------------------------------------------------------------------------
+// MainWindow.xaml.cs
+//
+// Copyright 2011, Nick Gravelyn.
+// Licensed under the terms of the Ms-PL: http://www.microsoft.com/opensource/licenses.mspx#Ms-PL
+//-----------------------------------------------------------------------------
+#endregion
+
+using System;
+using System.Diagnostics;
+using System.Windows;
+using Microsoft.Xna.Framework;
+using Primitives3D;
+using GameProgram;
+using Microsoft.Xna.Framework.Input;
+using System.Windows.Interop;
+using System.Windows.Controls;
+
+namespace WpfHostedXna
+{
+    public partial class MainWindow : Window
+    {
+        private CubePrimitive cube;
+        private Window1 testWindow = new Window1();
+        private Window1 testWindow1 = new Window1();
+        private Window1 testWindow2 = new Window1();
+        private Window1 testWindow3 = new Window1();
+        private Game1WPFAdapter game;
+        private GameTime gameTime;
+
+
+        // We use a Stopwatch to track our total time for cube animation
+        private Stopwatch watch = new Stopwatch();
+        private Stopwatch updateWatch = new Stopwatch();
+
+        // A yaw and pitch applied to the second viewport based on input
+        private float yaw = 0f;
+        private float pitch = 0f;
+
+        // The color applied to the cube in the second viewport
+        Color cubeColor = Color.Orange;
+
+        public MainWindow()
+        {   
+          InitializeComponent();
+
+          testWindow.Height = 75;
+          testWindow.Width  = 550;
+          testWindow.Left = 380;
+          testWindow.Top = 0;
+
+          testWindow1.Height = 540;
+          testWindow1.Width = 200;
+          testWindow1.Left = 0;
+          testWindow1.Top = 80;
+
+          testWindow2.Height = 325;
+          testWindow2.Width = 375;
+          testWindow2.Left = 0;
+          testWindow2.Top = 630;
+
+          testWindow3.Height = 325;
+          testWindow3.Width = 375;
+          testWindow3.Left = 885;
+          testWindow3.Top = 630;
+
+          WindowStyle = WindowStyle.None;
+          WindowState = WindowState.Maximized;
+
+        }
+
+        /// <summary>
+        /// Invoked after either control has created its graphics device.
+        /// </summary>
+        private void loadContent(object sender, GraphicsDeviceEventArgs e)
+        {
+          Mouse.WindowHandle = xnaControl2.Handle;// WindowInteropHelper( this ).Handle;
+          System.Windows.Application.Current.MainWindow = this;
+          
+          game = new Game1WPFAdapter( e.GraphicsDevice, xnaControl2.Services);
+          
+            testWindow.Owner = this;
+            testWindow1.Owner = this;
+            testWindow2.Owner = this;
+            testWindow3.Owner = this;
+            ////testDialogWindow.WindowStyle = WindowStyle.None;
+            ////testDialogWindow.AllowsTransparency = true;
+            ////testDialogWindow.Background = System.Windows.Media.Brushes.Black;
+            ////testDialogWindow.Opacity = 0.2;
+
+            testWindow.Show();
+            testWindow1.Show();
+            testWindow2.Show();
+            testWindow3.Show();            
+
+            game.Initialize();
+            game.LoadContent();
+
+            // Because this same event is hooked for both controls, we check if the Stopwatch
+            // is running to avoid loading our content twice.
+            if (!watch.IsRunning)
+            {
+              // Create our 3D cube object
+              //cube = new CubePrimitive( e.GraphicsDevice );
+
+              // Start the watch now that we're going to be starting our draw loop
+              watch.Start();
+              updateWatch.Start();
+            }
+            
+        }
+
+        /// <summary>
+        /// Invoked when our first control is ready to render.
+        /// </summary>
+        private void xnaControl1_RenderXna(object sender, GraphicsDeviceEventArgs e)
+        {
+            e.GraphicsDevice.Clear(Color.CornflowerBlue);
+
+            // Compute some values for the cube rotation
+            float time = (float)watch.Elapsed.TotalSeconds;
+            float yaw = time * 0.4f;
+            float pitch = time * 0.7f;
+            float roll = time * 1.1f;
+
+            // Create the world-view-projection matrices for the cube and camera
+            Matrix world = Matrix.CreateFromYawPitchRoll(yaw, pitch, roll);
+            Matrix view = Matrix.CreateLookAt(new Vector3(0, 0, 2.5f), Vector3.Zero, Vector3.Up);
+            Matrix projection = Matrix.CreatePerspectiveFieldOfView(1, e.GraphicsDevice.Viewport.AspectRatio, 1, 10);
+
+            // Get the color from our sliders
+            Color color = Color.Gold;//new Color((float)rComponent.Value, (float)gComponent.Value, (float)bComponent.Value);
+
+            // Draw a cube
+            cube.Draw(world, view, projection, color);
+        }
+
+        /// <summary>
+        /// Invoked when our second control is ready to render.
+        /// </summary>
+        private void xnaControl2_RenderXna(object sender, GraphicsDeviceEventArgs e)
+        {
+            e.GraphicsDevice.Clear(Color.CornflowerBlue);
+
+            // Create the world-view-projection matrices for the cube and camera
+            Matrix world = Matrix.CreateFromYawPitchRoll(yaw, pitch, 0f);
+            Matrix view = Matrix.CreateLookAt(new Vector3(0, 0, 2.5f), Vector3.Zero, Vector3.Up);
+            Matrix projection = Matrix.CreatePerspectiveFieldOfView(1, e.GraphicsDevice.Viewport.AspectRatio, 1, 10);
+
+            // Get the color from our sliders
+            Color color = Color.Gold;//new Color((float)rComponent.Value, (float)gComponent.Value, (float)bComponent.Value);
+
+            gameTime = new GameTime( watch.Elapsed, updateWatch.Elapsed );
+            game.Update( gameTime );
+            updateWatch.Restart();
+            game.Draw(gameTime);
+
+          
+            // Draw a cube
+            //cube.Draw(world, view, projection, cubeColor);
+        }
+
+        // Invoked when the mouse moves over the second viewport
+        private void xnaControl2_MouseMove(object sender, HwndMouseEventArgs e)
+        {
+
+
+          game.updateCameraOffset();
+            // If the left or right buttons are down, we adjust the yaw and pitch of the cube
+            //if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed ||
+            //    e.RightButton == System.Windows.Input.MouseButtonState.Pressed)
+            //{
+            //    yaw += (float)(e.Position.X - e.PreviousPosition.X) * .01f;
+            //    pitch += (float)(e.Position.Y - e.PreviousPosition.Y) * .01f;
+            //}
+          if (e.MiddleButton == System.Windows.Input.MouseButtonState.Pressed)
+          {
+            xnaControl2.CaptureMouse();
+
+          }
+          else
+          {
+            xnaControl2.ReleaseMouseCapture();
+          }
+
+          
+        }
+
+        // We use the left mouse button to do exclusive capture of the mouse so we can drag and drag
+        // to rotate the cube without ever leaving the control
+        private void xnaControl2_HwndLButtonDown(object sender, HwndMouseEventArgs e)
+        {
+          
+
+          //if (xnaControl2.IsFocused)
+          //{
+          //game.Mouse.Update();
+
+          //}
+          
+            
+        }
+
+        private void xnaControl2_HwndLButtonUp(object sender, HwndMouseEventArgs e)
+        {
+          
+            xnaControl2.ReleaseMouseCapture();
+        }
+
+        private void xnaControl2_HwndMouseWheel( object sender, HwndMouseEventArgs e )
+        {          
+            
+        }
+
+      
+
+        // We have three simple event handlers for the Red, Green, and Blue buttons
+        private void redButton_Click(object sender, RoutedEventArgs e) { cubeColor = Color.Red; }
+        private void greenButton_Click(object sender, RoutedEventArgs e) { cubeColor = Color.Green; }
+        private void blueButton_Click(object sender, RoutedEventArgs e) { cubeColor = Color.Blue; }
+    }
+}
+

WpfHostedXnaApplication/NoGdiWindow.cs

+namespace System.Windows.Controls
+{
+    using System;
+    using System.Collections.Generic;
+    using System.ComponentModel;
+    using System.Runtime.InteropServices;
+    using System.Windows;
+    using System.Windows.Controls;
+    using System.Windows.Input;
+    using System.Windows.Interop;
+    using System.Windows.Media;
+    using System.Windows.Shapes;
+    using Mvvm;
+
+    /// <summary>
+    /// Removes all GDI stuff from a WPF Window, and makes it resizeable.
+    /// </summary>
+    /// <remarks>Root visual should be a Grid.</remarks>
+    public partial class NoGdiWindow : Window, INotifyPropertyChanged
+    {
+        /// <summary>
+        /// Win32 Handle.
+        /// </summary>
+        private HwndSource hwndSource;
+
+        /// <summary>
+        /// Close Command
+        /// </summary>
+        private DelegateCommand closeCommand;
+
+        /// <summary>
+        /// Maximize Command
+        /// </summary>
+        private DelegateCommand maximizeCommand;
+
+        /// <summary>
+        /// Minimize Command
+        /// </summary>
+        private DelegateCommand minimizeCommand;
+
+        /// <summary>
+        /// Links a cursor to each direction.
+        /// </summary>
+        private Dictionary<ResizeDirection, Cursor> cursors = new Dictionary<ResizeDirection, Cursor> 
+        {
+            { ResizeDirection.Top, Cursors.SizeNS },
+            { ResizeDirection.Bottom, Cursors.SizeNS },
+            { ResizeDirection.Left, Cursors.SizeWE },
+            { ResizeDirection.Right, Cursors.SizeWE },
+            { ResizeDirection.TopLeft, Cursors.SizeNWSE },
+            { ResizeDirection.BottomRight, Cursors.SizeNWSE },
+            { ResizeDirection.TopRight, Cursors.SizeNESW },
+            { ResizeDirection.BottomLeft, Cursors.SizeNESW } 
+        };
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="NoGdiWindow"/> class.
+        /// </summary>
+        public NoGdiWindow()
+        {
+            // Commands
+            this.closeCommand = new Mvvm.DelegateCommand(this.Close_Executed);
+            this.maximizeCommand = new Mvvm.DelegateCommand(this.Maximize_Executed);
+            this.minimizeCommand = new Mvvm.DelegateCommand(this.Minimize_Executed);
+
+            // Events
+            this.SourceInitialized += this.ResizeableWindow_SourceInitialized;
+            this.Initialized += this.ResizeableWindow_Initialized;
+            this.StateChanged += this.ResizeableWindow_StateChanged;
+        }
+
+        /// <summary>
+        /// Occurs when a property value changes.
+        /// </summary>
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        /// <summary>
+        /// Resize Direction
+        /// </summary>
+        private enum ResizeDirection
+        {
+            Left = 1,
+            Right = 2,
+            Top = 3,
+            TopLeft = 4,
+            TopRight = 5,
+            Bottom = 6,
+            BottomLeft = 7,
+            BottomRight = 8,
+        }
+
+        public bool UsesWindowsFormsHost { get; set; }
+
+        /// <summary>
+        /// Gets the close command.
+        /// </summary>
+        public ICommand CloseCommand
+        {
+            get { return this.closeCommand; }
+        }
+
+        /// <summary>
+        /// Gets the maximize command.
+        /// </summary>
+        public ICommand MaximizeCommand
+        {
+            get { return this.maximizeCommand; }
+        }
+
+        /// <summary>
+        /// Gets the minimize command.
+        /// </summary>
+        public ICommand MinimizeCommand
+        {
+            get { return this.minimizeCommand; }
+        }
+
+        /// <summary>
+        /// Gets the visibility of the maximize button.
+        /// </summary>
+        public Visibility MaximizeButtonVisibility
+        {
+            get
+            {
+                if (this.WindowState == System.Windows.WindowState.Normal)
+                {
+                    return System.Windows.Visibility.Visible;
+                }
+
+                return System.Windows.Visibility.Collapsed;
+            }
+        }
+
+        /// <summary>
+        /// Gets the visibility of the restore button.
+        /// </summary>
+        public Visibility RestoreButtonVisibility
+        {
+            get
+            {
+                if (this.WindowState == System.Windows.WindowState.Maximized)
+                {
+                    return System.Windows.Visibility.Visible;
+                }
+
+                return System.Windows.Visibility.Collapsed;
+            }
+        }
+
+        /// <summary>
+        /// Handles the MouseLeftButtonDown event of the header part of the window.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
+        protected void Header_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+        {
+            if (e.ClickCount > 1)
+            {
+                this.MaximizeCommand.Execute(null);
+            }
+            else if (e.LeftButton == MouseButtonState.Pressed)
+            {
+                this.DragMove();
+            }
+        }
+
+        [DllImport("user32.dll", CharSet = CharSet.Auto)]
+        private static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
+
+        /// <summary>
+        /// Gets the resize direction from the name of the handle rectangle.
+        /// </summary>
+        /// <param name="name">The name.</param>
+        /// <returns>A ResizeDirection.</returns>
+        private static ResizeDirection GetDirectionFromName(string name)
+        {
+            // Assumes the drag handels are all named *DragHandle
+            string enumName = name.Replace("DragHandle", string.Empty);
+            return (ResizeDirection)Enum.Parse(typeof(ResizeDirection), enumName);
+        }
+
+        /// <summary>
+        /// Handles the Initialized event of the ResizeableWindow control.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
+        private void ResizeableWindow_Initialized(object sender, EventArgs e)
+        {
+            // Visual Properties
+            this.WindowStyle = System.Windows.WindowStyle.None;
+
+            // Real transparency only works above Windows XP and if there are no WindowsFormsHost controls
+            if ((Environment.OSVersion.Version.Major > 5) & (!this.UsesWindowsFormsHost))
+            {
+                Grid root = this.Content as Grid;
+
+                if (root != null)
+                {
+                    this.AllowsTransparency = true;
+                    this.Background = new SolidColorBrush(Colors.Transparent);
+
+                    root.Children.Add(this.GetResizeHandleRectangle("TopDragHandle", HorizontalAlignment.Stretch, VerticalAlignment.Top));
+                    root.Children.Add(this.GetResizeHandleRectangle("RightDragHandle", HorizontalAlignment.Right, VerticalAlignment.Stretch));
+                    root.Children.Add(this.GetResizeHandleRectangle("BottomDragHandle", HorizontalAlignment.Stretch, VerticalAlignment.Bottom));
+                    root.Children.Add(this.GetResizeHandleRectangle("LeftDragHandle", HorizontalAlignment.Left, VerticalAlignment.Stretch));
+                    root.Children.Add(this.GetResizeHandleRectangle("TopLeftDragHandle", HorizontalAlignment.Left, VerticalAlignment.Top));
+                    root.Children.Add(this.GetResizeHandleRectangle("TopRightDragHandle", HorizontalAlignment.Right, VerticalAlignment.Top));
+                    root.Children.Add(this.GetResizeHandleRectangle("BottomRightDragHandle", HorizontalAlignment.Right, VerticalAlignment.Bottom));
+                    root.Children.Add(this.GetResizeHandleRectangle("BottomLeftDragHandle", HorizontalAlignment.Left, VerticalAlignment.Bottom));
+                }
+            }
+        }
+
+        /// <summary>
+        /// Handles the SourceInitialized event of the ResizeableWindow control.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
+        private void ResizeableWindow_SourceInitialized(object sender, EventArgs e)
+        {
+            this.hwndSource = PresentationSource.FromVisual((Visual)sender) as HwndSource;
+        }
+
+        /// <summary>
+        /// Resizes the ResizeableWindow control.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The <see cref="System.Windows.Input.MouseEventArgs"/> instance containing the event data.</param>
+        private void ResizeableWindow_ResizeIfPressed(object sender, MouseEventArgs e)
+        {
+            FrameworkElement element = sender as FrameworkElement;
+            ResizeDirection direction = GetDirectionFromName(element.Name);
+
+            if (e.LeftButton == MouseButtonState.Pressed)
+            {
+                SendMessage(this.hwndSource.Handle, 0x112, (IntPtr)(61440 + direction), IntPtr.Zero);
+            }
+        }
+
+        /// <summary>
+        /// Handles the StateChanged event of the ResizeableWindow control.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
+        private void ResizeableWindow_StateChanged(object sender, EventArgs e)
+        {
+            this.PropertyChanged.RaiseAll(this);
+        }
+
+        /// <summary>
+        /// Close executed.
+        /// </summary>
+        /// <param name="o">The ignored parameter.</param>
+        private void Close_Executed(object o)
+        {
+            this.Close();
+        }
+
+        /// <summary>
+        /// Maximize executed.
+        /// </summary>
+        /// <param name="o">The o.</param>
+        private void Maximize_Executed(object o)
+        {
+            if (this.WindowState == System.Windows.WindowState.Maximized)
+            {