Spritebatch不能在winforms中工作

我在应用程序中心使用Winforms示例,一切工作正常,除了我的spritebatch不会绘制任何东西,除非我在Draw方法中调用Invalidate。 我有我的初始化方法:

Application.Idle += delegate { Invalidate(); }; 

我用了一个断点,它确实使我的程序无效,并且正在调用我的绘图方法。 我没有得到spritebatch的错误,所有的纹理加载,我只是没有看到在屏幕上的任何东西。 这是我有的代码:

  protected override void Draw() { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); tileSheet.Draw(spriteBatch); foreach (Image img in selector) img.Draw(spriteBatch); spriteBatch.End(); } 

但是当我这样做:

  protected override void Draw() { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); tileSheet.Draw(spriteBatch); foreach (Image img in selector) img.Draw(spriteBatch); spriteBatch.End(); Invalidate(); } 

那么突然之间的绘图开始工作! 但问题是它冻结了一切,只有控制得到更新。 我能做些什么来解决这个问题? 真令人沮丧。

要获得持续更新而不降低UI性能,您需要使用以下技巧挂钩到Windows消息队列中:

 public static class NativeMethods { [StructLayout(LayoutKind.Sequential)] public struct Message { public IntPtr hWnd; public UInt32 msg; public IntPtr wParam; public IntPtr lParam; public UInt32 time; public Point p; } [SuppressUnmanagedCodeSecurity] // We won't use this maliciously [DllImport("User32.dll", CharSet = CharSet.Auto)] public static extern bool PeekMessage(out Message msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags); } 

用法是这样的(对于奖励积分,我添加了我的固定时间步代码):

  // Hook up idle event (in Form load or wherever) Application.Idle += delegate { Application_Idle(); }; void Application_Idle(object sender, EventArgs e) { while (AppStillIdle()) Tick(); // This contains your Update() and Draw() loop } // Check if any messages are waiting on the queue // We only want to keep ticking whilst there are none. private bool AppStillIdle() { NativeMethods.Message msg; return !NativeMethods.PeekMessage(out msg, Handle, 0, 0, 0); } // Tick function handles the fixed timestep and Update/Draw const float TARGET_ELAPSED_TIME = 0.0166667f; float elapsedSum = 0.0f; private void Tick() { float elapsed = (float)timer.Elapsed.TotalSeconds; timer.Reset(); timer.Start(); elapsedSum += elapsed; if (elapsedSum >= TARGET_ELAPSED_TIME) { // Game update and draw Update(TARGET_ELAPSED_TIME); Draw(); // INVALIDATE GRAPHICS DEVICE CONTROLS gdcLevel.Invalidate(); elapsedSum %= TARGET_ELAPSED_TIME; } // Return control to UI thread in case more messages arrive System.Threading.Thread.Sleep(0); } 

我的实现基于Tom Miller的博客文章: http : //blogs.msdn.com/b/tmiller/archive/2005/05/05/415008.aspx

另外floAr的答案引用肖恩的博客,其中包含几乎相同的代码: http : //blogs.msdn.com/b/shawnhar/archive/2010/12/06/when-winforms-met-game-loop.aspx

有一个由Shawn Hargreaves关于XNA与WinForms的非常好的职位,你应该明确地检查出来。

另外这里有两个教程,一个是WinForms和WPF中的 XNA,有一些更复杂的事件处理(都是德语)

也许尝试设置一个计时器并重建XNA的固定时间步骤。 这将在您的UI线程处理中排队定时器并更新绘图。 每当一个新的框架准备就绪时,无效将被调用。

 timer = new Timer(); timer.Interval = (int)TargetElapsedTime.TotalMilliseconds; timer.Tick += Tick; timer.Start(); Stopwatch stopWatch = Stopwatch.StartNew(); readonly TimeSpan TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 60); readonly TimeSpan MaxElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 10); TimeSpan accumulatedTime; TimeSpan lastTime; void Tick(object sender, EventArgs e) { TimeSpan currentTime = stopWatch.Elapsed; TimeSpan elapsedTime = currentTime - lastTime; lastTime = currentTime; if (elapsedTime > MaxElapsedTime) { elapsedTime = MaxElapsedTime; } accumulatedTime += elapsedTime; bool updated = false; while (accumulatedTime >= TargetElapsedTime) { Update(); Draw(); accumulatedTime -= TargetElapsedTime; updated = true; } if (updated) { Invalidate(); } } 

我希望这会让你开始!