2013-06-07 13 views
7

Jak utworzyć pętlę, która będzie wykonywana w sposób ciągły, gdy pętla komunikatów jest bezczynna w WPF?Jak zrobić pętlę renderowania w WPF?

Celem jest wykonanie długotrwałej aktualizacji graficznej, takiej jak odświeżenie PicktureBox, która może pochłonąć dowolne wolne zasoby, ale nie powinna zamrozić interfejsu użytkownika lub w inny sposób mieć pierwszeństwo przed innymi operacjami w wiadomości kolejka.

Zauważyłem, this blog post, który zapewnia kod do tego w aplikacji WinForm, ale nie wiem, jak to przetłumaczyć na aplikację WPF. Poniżej znajduje się kod należący do WinForms renderowania klasa pętla, że ​​zrobiłem na podstawie innego artykułu:

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

Twoje pytanie powinno być niezależne. Powinniśmy być w stanie odpowiedzieć na to bez potrzeby podążania za jakimikolwiek linkami. – Servy

+0

Niestety, szefie, czy teraz jest dla ciebie w porządku? – Pedro77

+0

Meh, wyjaśnienie, co chcesz zrobić, jest prawdopodobnie ważniejsze niż pokazanie kodu, chociaż z pewnością jest to lepsze niż zwykły link. – Servy

Odpowiedz

10

Najlepszym sposobem, aby to zrobić jest użycie zwrotnych na klatce dostarczonych przez statyczny CompositionTarget.Rendering imprezy.

+0

Dziękuję, wydaje się, że jest to właściwa droga. – Pedro77

Powiązane problemy