繁体   English   中英

为什么在事件循环开始之前释放控件时不执行 BeginInvoke 中的操作?

[英]Why isn't the action in BeginInvoke executed when a control is disposed before the event loop starts?

WinForms(NET Core 和 Framework)中的以下代码在运行 Application.DoEvents 时不会尝试 BeginInvoke 中的操作:

namespace BeginInvokeTest
{
    internal static class Program
    {
        /// <summary>
        ///  The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            ApplicationConfiguration.Initialize();

            bool executed;

            var form = new Form();
            form.Show();

            form.BeginInvoke(() => { executed = true; });

            form.Dispose();
            Application.DoEvents();
        }
    }
}

但是,如果我在 Application.DoEvents 之后移动 form.Dispose,则执行该操作。 所以我知道如果在启动消息循环之前处置了拥有控件,则 BeginInvoke 排队的消息将被忽略。

有谁知道在 WinForms 中的哪个位置强制/实施了这种行为; 释放控件时,WinForms 会从队列中删除消息吗?

(查看了 GitHub 中的源代码,但无法锻炼发生这种情况的位置/方式)

谢谢!

您要查找的代码Control.DestoryHandle中,由Control.Dispose调用

// If we're not recreating the handle, then any items in the thread callback list will
// be orphaned.  An orphaned item is bad, because it will cause the thread to never
// wake up.  So, we put exceptions into all these items and wake up all threads.
// If we are recreating the handle, then we're fine because recreation will re-post
// the thread callback message to the new handle for us.
//
if (!RecreatingHandle) {                
    if (threadCallbackList != null) {
        lock (threadCallbackList) {
            Exception ex = new System.ObjectDisposedException(GetType().Name);
 
            while (threadCallbackList.Count > 0) {
                ThreadMethodEntry entry = (ThreadMethodEntry)threadCallbackList.Dequeue();
                entry.exception = ex;
                entry.Complete();
            }
        }
    }
}

如您所见,如果未重新创建句柄,则所有尚未调度的剩余回调都将设置为具有异常。 因为这是异步的,所以除非您调用EndInvoke ,否则您不会看到异常。

如果回调已经完成,您也不会看到任何异常。 当您调用DoEvents时,队列中的任何 window 消息都会被抽出。 调用的回调通过 window 消息队列调度,因此所有回调都在您调用DoEvents时完成。 所以当你之后Dispose时,即使你调用EndInvoke也不例外,因为回调已经完成。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM