首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >托管.NET和WinForms,当ShowDialog of .NET窗口返回时,SynchronizationContexts被重置

托管.NET和WinForms,当ShowDialog of .NET窗口返回时,SynchronizationContexts被重置
EN

Stack Overflow用户
提问于 2015-09-07 13:15:50
回答 1查看 202关注 0票数 2

我们在德尔菲应用程序中托管了.NET 4.0和许多WinForms窗口。

我们发现,每当德尔福的ShowDialog在.NET表单上调用时,当表单关闭时,SynchronizationContext.Current会被重置回使用线程池的System.Threading.SynchronizationContext

我们是否有办法强迫这种情况不发生,或者欺骗代码将其重置回WindowsFormsSynchronizationContext,而不是将必要的代码添加到对ShowDialog的每次调用中。

我们已经托管.NET多年了,但直到最近才开始进行涉及异步代码的工作,而这在我们打开的第二个窗口上失败了。

您可以复制我们在这个简单程序中看到的内容,只需创建一个新的WinForms项目并将这些代码粘贴到Program.cs中:

代码语言:javascript
运行
复制
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;

namespace WindowsFormsApplication4
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Debug.WriteLine("P1: " + SynchronizationContext.Current);

            using (var fm = new Form())
            {
                fm.Load += (s, e) => Debug.WriteLine("P2: " + SynchronizationContext.Current);
                fm.ShowDialog();
            }

            Debug.WriteLine("P3: " + SynchronizationContext.Current);
        }
    }
}

产出:

代码语言:javascript
运行
复制
P1: 
P2: System.Windows.Forms.WindowsFormsSynchronizationContext
P3: System.Threading.SynchronizationContext

基本上:

  • 在打开表单之前,SynchronizationContext.Currentnull
  • 在Form.Load事件中,SynchronizationContext.CurrentWindowsFormsSynchronizationContext的一个实例
  • 窗体关闭后,SynchronizationContext.Current已重新设置为System.Threading.SynchronizationContext

我们尝试过各种技巧来欺骗这段代码:

  • 构造隐藏形式
  • 构造隐藏表单,并在调用ShowDialog时使其成为所有者
  • 构造可见表单(用Show而不是ShowDialog显示)

在查看了参考源之后,我们认为我们已经确定了可能的原因,在这一行: Applicationcs#3445和以后:

代码语言:javascript
运行
复制
messageLoopCount--;

if (messageLoopCount == 0) {
    // If last message loop shutting down, install the
    // previous op [....] context in place before we started the first
    // message loop.
    WindowsFormsSynchronizationContext.Uninstall(false);
}

由于主消息循环是由德尔福完成的,.NET对此一无所知,因此,当.NET认为世界即将结束时,第一个打开will的窗口关闭后,最终会摧毁整个世界。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-09-07 14:21:45

将WindowsFormsSynchronizationContext包装在上下文中。比如:

代码语言:javascript
运行
复制
class MySynchronizationContext : SynchronizationContext
{
    private SynchronizationContext context = new WindowsFormsSynchronizationContext();

    public override SynchronizationContext CreateCopy()
    {
        return context.CreateCopy();
    }

    public override bool Equals(object obj)
    {
        return context.Equals(obj);
    }

    public override int GetHashCode()
    {
        return context.GetHashCode();
    }

    public override void OperationCompleted()
    {
        context.OperationCompleted();
    }

    public override void OperationStarted()
    {
        context.OperationStarted();
    }

    public override void Post(SendOrPostCallback d, object state)
    {
        context.Post(d, state);
    }

    public override void Send(SendOrPostCallback d, object state)
    {
        context.Send(d, state);
    }

    public override string ToString()
    {
        return "Wrapped";
    }

    public override int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
    {
        return context.Wait(waitHandles, waitAll, millisecondsTimeout);
    }
}

并在任何窗口窗体调用之前设置它。在这种情况下,它将不会被取代:

代码语言:javascript
运行
复制
        /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        MySynchronizationContext context = new MySynchronizationContext();
        SynchronizationContext.SetSynchronizationContext(context);
        Debug.WriteLine("P1: " + SynchronizationContext.Current );

        using (var fm = new Form())
        {
            fm.Load += (s, e) => Debug.WriteLine("P2: " + SynchronizationContext.Current);
            fm.ShowDialog();
        }

        Debug.WriteLine("P3: " + SynchronizationContext.Current );
    }

希望能帮上忙。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32439669

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档