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!

  • Participants
  • Parent commits 4f34347

Comments (0)

Files changed (25)

File 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>

File 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
+    {
+    }
+}

File 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
+    }
+}

File 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;
+        }
+    }
+}

File 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);
+        }
+    }
+}

File 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;
+        }
+    }
+}

File 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;
+    }
+}

File 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
+    }
+}

File 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
+    }
+}

File 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));
+            }
+        }
+    }
+}

File 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>

File 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; }
+    }
+}
+

File 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();
+        }