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

8

如何在WPF中创建一个循环,使其在消息循环处于空闲状态时持续执行?

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

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

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:
            //https://dev59.com/7UjSa4cB1Zd3GeqPCyOg
            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
    }
}

2
你的问题应该是自包含的。我们应该能够回答它,而不需要跟随任何链接。 - Servy
对不起,老板,现在可以了吗? - Pedro77
嗯,解释你想要做什么比展示代码更重要,虽然展示代码肯定比只有一个链接好。 - Servy
2
我来这里是为了帮助您改进问题,使其成为更好的问题,从而更有可能获得高质量的答案,而不仅仅被忽视。如果您对改进问题没有兴趣,那没关系,但您的编辑表明您有兴趣。 - Servy
1
Application.Idle: 由于这是一个静态事件,当您的应用程序被处理或内存泄漏时,您必须分离事件处理程序。 - Reza Aghaei
2个回答

13

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接