2013-06-07 32 views
7

Làm cách nào để tạo vòng lặp liên tục được thực hiện bất cứ khi nào vòng lặp tin nhắn không hoạt động trong WPF? Mục tiêu ở đây là để thực hiện một số cập nhật đồ họa dài chạy, chẳng hạn như làm mới PicktureBox, có khả năng tiêu thụ bất kỳ tài nguyên miễn phí nào nhưng không nên đóng băng giao diện người dùng hoặc ưu tiên hơn bất kỳ hoạt động nào khác trong thư xếp hàng.Làm thế nào để tạo một vòng lặp render trong WPF?

Tôi nhận thấy this blog post cung cấp mã để thực hiện việc này trong ứng dụng winforms, nhưng tôi không biết cách dịch nó sang ứng dụng WPF. Dưới đây là mã của một WinForms render lớp vòng lặp mà tôi thực hiện dựa trên các bài viết khác:

using System; 
using System.Runtime.InteropServices; 
using System.Threading; 
using System.Windows.Forms; 

namespace Utilities.UI 
{ 
    /// <summary> 
    /// WinFormsAppIdleHandler implements a WinForms Render Loop (max FPS possible). 
    /// Reference: http://blogs.msdn.com/b/tmiller/archive/2005/05/05/415008.aspx 
    /// </summary> 
    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; 
     } 

     /// <summary> 
     /// Singleton from: 
     /// http://csharpindepth.com/Articles/General/Singleton.aspx 
     /// </summary> 
     private static readonly Lazy<WinFormsAppIdleHandler> lazy = new Lazy<WinFormsAppIdleHandler>(() => new WinFormsAppIdleHandler()); 
     public static WinFormsAppIdleHandler Instance { get { return lazy.Value; } } 

     /// <summary> 
     /// Gets or sets if must fire ApplicationLoopDoWork event. 
     /// </summary> 
     public bool Enabled { get; set; } 

     /// <summary> 
     /// Gets or sets the minimum time betwen ApplicationLoopDoWork fires. 
     /// </summary> 
     public int SleepTime { get; set; } 

     /// <summary> 
     /// Fires while the UI is free to work. Sleeps for "SleepTime" ms. 
     /// </summary> 
     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; 
      } 
     } 

     /// <summary> 
     /// FINALMENTE! Imagem ao vivo sem travar! Muito bom! 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     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); 
      } 
     } 

     /// <summary> 
     /// Gets if the app still idle. 
     /// </summary> 
     /// <returns></returns> 
     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 
    } 
} 
+1

Câu hỏi của bạn nên được khép kín. Chúng ta sẽ có thể trả lời nó mà không cần theo bất kỳ liên kết nào. – Servy

+0

Xin lỗi ông chủ, bây giờ có ổn không? – Pedro77

+0

Meh, giải thích những gì bạn muốn làm có lẽ quan trọng hơn việc hiển thị mã, mặc dù điều đó chắc chắn tốt hơn chỉ là một liên kết. – Servy

Trả lời

10

Cách tốt nhất để làm điều này là sử dụng callbacks mỗi khung được cung cấp bởi các sự kiện tĩnh CompositionTarget.Rendering.

+0

Cảm ơn bạn, có vẻ như đó là cách phù hợp để đi. – Pedro77

Các vấn đề liên quan