如何在WPF中创建渲染循环?

如何在WPF中消息循环空闲时创建一个连续执行的循环?

这里的目标是执行一些长时间运行的图形更新,例如刷新PicktureBox ,它能够消耗任何可用的免费资源,但不应该冻结UI或以其他方式优先于消息队列中的任何其他操作。

我注意到这篇博客文章提供了在winforms应用程序中执行此操作的代码,但我不知道如何将其转换为WPF应用程序。 下面是我根据另一篇文章制作的WinForms渲染循环类的代码:

 using System; using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; namespace Utilities.UI { ///  /// WinFormsAppIdleHandler implements a WinForms Render Loop (max FPS possible). /// Reference: http://blogs.msdn.com/b/tmiller/archive/2005/05/05/415008.aspx ///  public sealed class WinFormsAppIdleHandler { private readonly object _completedEventLock = new object(); private event EventHandler _applicationLoopDoWork; //PRIVATE Constructor private WinFormsAppIdleHandler() { Enabled = false; SleepTime = 10; Application.Idle += Application_Idle; } ///  /// Singleton from: /// http://csharpindepth.com/Articles/General/Singleton.aspx ///  private static readonly Lazy lazy = new Lazy(() => new WinFormsAppIdleHandler()); public static WinFormsAppIdleHandler Instance { get { return lazy.Value; } } ///  /// Gets or sets if must fire ApplicationLoopDoWork event. ///  public bool Enabled { get; set; } ///  /// Gets or sets the minimum time betwen ApplicationLoopDoWork fires. ///  public int SleepTime { get; set; } ///  /// Fires while the UI is free to work. Sleeps for "SleepTime" ms. ///  public event EventHandler ApplicationLoopDoWork { //Reason of using locks: //http://stackoverflow.com/questions/1037811/c-thread-safe-events add { lock (_completedEventLock) _applicationLoopDoWork += value; } remove { lock (_completedEventLock) _applicationLoopDoWork -= value; } } ///  /// FINALMENTE! Imagem ao vivo sem travar! Muito bom! ///  ///  ///  private void Application_Idle(object sender, EventArgs e) { //Try to update interface while (Enabled && IsAppStillIdle()) { OnApplicationIdleDoWork(EventArgs.Empty); //Give a break to the processor... :) //8 ms -> 125 Hz //10 ms -> 100 Hz Thread.Sleep(SleepTime); } } private void OnApplicationIdleDoWork(EventArgs e) { var handler = _applicationLoopDoWork; if (handler != null) { handler(this, e); } } ///  /// Gets if the app still idle. ///  ///  private static bool IsAppStillIdle() { bool stillIdle = false; try { Message msg; stillIdle = !PeekMessage(out msg, IntPtr.Zero, 0, 0, 0); } catch (Exception e) { //Should never get here... I hope... MessageBox.Show("IsAppStillIdle() Exception. Message: " + e.Message); } return stillIdle; } #region Unmanaged Get PeekMessage // http://blogs.msdn.com/b/tmiller/archive/2005/05/05/415008.aspx [System.Security.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); #endregion } } 

执行此操作的最佳方法是使用静态CompositionTarget.Rendering事件提供的每帧回调。