我们在德尔菲应用程序中托管了.NET 4.0和许多WinForms窗口。
我们发现,每当德尔福的ShowDialog
在.NET表单上调用时,当表单关闭时,SynchronizationContext.Current
会被重置回使用线程池的System.Threading.SynchronizationContext
。
我们是否有办法强迫这种情况不发生,或者欺骗代码将其重置回WindowsFormsSynchronizationContext
,而不是将必要的代码添加到对ShowDialog
的每次调用中。
我们已经托管.NET多年了,但直到最近才开始进行涉及异步代码的工作,而这在我们打开的第二个窗口上失败了。
您可以复制我们在这个简单程序中看到的内容,只需创建一个新的WinForms项目并将这些代码粘贴到Program.cs中:
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);
}
}
}
产出:
P1:
P2: System.Windows.Forms.WindowsFormsSynchronizationContext
P3: System.Threading.SynchronizationContext
基本上:
SynchronizationContext.Current
是null
。SynchronizationContext.Current
是WindowsFormsSynchronizationContext
的一个实例SynchronizationContext.Current
已重新设置为System.Threading.SynchronizationContext
。我们尝试过各种技巧来欺骗这段代码:
ShowDialog
时使其成为所有者Show
而不是ShowDialog
显示)在查看了参考源之后,我们认为我们已经确定了可能的原因,在这一行: Applicationcs#3445和以后:
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的窗口关闭后,最终会摧毁整个世界。
发布于 2015-09-07 14:21:45
将WindowsFormsSynchronizationContext包装在上下文中。比如:
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);
}
}
并在任何窗口窗体调用之前设置它。在这种情况下,它将不会被取代:
/// <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 );
}
希望能帮上忙。
https://stackoverflow.com/questions/32439669
复制相似问题