Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从backgroundworker返回到Winforms应用程序中托管的WPF对话框中的调用线程_C#_Wpf_Multithreading_Backgroundworker_Synchronizationcontext - Fatal编程技术网

C# 从backgroundworker返回到Winforms应用程序中托管的WPF对话框中的调用线程

C# 从backgroundworker返回到Winforms应用程序中托管的WPF对话框中的调用线程,c#,wpf,multithreading,backgroundworker,synchronizationcontext,C#,Wpf,Multithreading,Backgroundworker,Synchronizationcontext,我们有一个Winforms应用程序,它启动一个WPF对话框,我称之为向导。向导的目的是打开多个文本文件并将其内容保存到数据库中。将这些文件保存到数据库所需的时间从15秒到60秒不等。为了使向导UI具有响应性,将文本文件保存到数据库的过程是在BackgroundWorker线程上完成的。不幸的是,由于Winforms主机应用程序中的一些遗留代码,向导在80-90%的时间内完全没有响应。因此,向导在其自己的工作线程上启动 //Put the Wizard on a separate thread t

我们有一个Winforms应用程序,它启动一个WPF对话框,我称之为向导。向导的目的是打开多个文本文件并将其内容保存到数据库中。将这些文件保存到数据库所需的时间从15秒到60秒不等。为了使向导UI具有响应性,将文本文件保存到数据库的过程是在BackgroundWorker线程上完成的。不幸的是,由于Winforms主机应用程序中的一些遗留代码,向导在80-90%的时间内完全没有响应。因此,向导在其自己的工作线程上启动

//Put the Wizard on a separate thread to maintain UI  //responsiveness during the export process Thread t = new Thread(LaunchBatchExportWizardView); t.SetApartmentState(ApartmentState.STA); t.Name = "WizardThread"; t.Start(); 总之,我们有三个主线程,支持Winforms主机的主线程、向导线程和BackgroundWorker线程。用户可以通过单击向导上的按钮暂停此导出过程,该按钮将向BackgroundWorker线程发送CancelAsync消息。在BackgroundWorker\u DoWork事件处理程序中,我们检查此取消消息,如果找到,则停止处理并返回。这将触发BackgroundWorker_RunWorkerCompleted事件处理程序,在该处理程序中,我可以使用thread.CurrentThread.Name检查控件已返回到的线程的标识

用户第一次暂停BackgroundWorker进程时,控件将返回到向导线程。如果用户希望恢复导出过程,我们将调用RunWorkerAsync,它将依次启动BackgroundWorker\u DoWork事件处理程序。通过观察,我可以看到这个处理程序并没有使用它以前使用过的同一个线程,而是使用了线程池中的一个新线程。出于调试目的,我给这个线程起了一个名字

           if(Thread.CurrentThread.Name == null) {    Thread.CurrentThread.Name = "MyBackgroundWorkerThread"  + "_" + _threadCounter.ToString();     _threadCounter++; } 第一个BackgroundWorker线程名为MyBackgroundWorkerThread_1,第二个线程名为MyBackgroundWorkerThread_2,以此类推

稍后,当用户决定再次暂停进程时,控件不会像第一次一样返回到BackgroundWorker\u RunWorkerCompleted事件处理程序中的向导线程,而是返回到某个新线程。但是,这并不是致命的,用户仍然可以继续,导出过程将继续进行

但是,当我们试图在数据库连接丢失的情况下启动自定义警告对话框时,就会出现问题。显然,如果向导无法与数据库通信,它将无法执行其主要任务。如果我们在一个或多个暂停/恢复周期后启动此对话框,则会抛出一个异常,并显示消息调用线程必须是STA,因为许多UI元素都需要这样做。由于这一要求,向导线程被显式设置为查看上面的相关代码,因此如果在任何暂停/恢复周期之前发生数据库连接丢失,则一切正常。这个新线程显然不是STA,因此会引发异常

我尝试的一个选项是测试,看看在启动DatabaseConnectivityLoss对话框的时候,我们是否在向导线程上。由于向导线程是一个显式命名的线程(请参见上面的代码),因此我只是测试当前线程的name属性是否为null:

if (Thread.CurrentThread.Name == null) {  if (Application.Current == null)  {       new Application();   }   Thread t = new Thread(LaunchDatabaseConnectivityLossDialog);   t.SetApartmentState(ApartmentState.STA);   t.Name = "NewStaThread";   t.Start(); } 这可以在没有前面提到的异常的情况下启动对话框,但是当我们尝试在连接恢复后恢复导出过程时,应用程序将挂起

我尝试的第二件事是设置SynchronizationContext变量来保存对向导线程的引用。据我所知,我可以使用此引用在向导线程上启动我的DatabaseConnectivityLoss对话框,而不管在任何时候哪个线程是当前线程。为此,我在向导的构造函数中设置了此变量:

_synchronizationContext = SynchronizationContext.Current;  if (_synchronizationContext == null)  {//always true in my case because the wizard is a child of a Winforms app       _synchronizationContext = new SynchronizationContext();  } 但是,当我稍后尝试使用此SynchronizationContext强制将代码返回到向导线程时,它失败了:

         `_synchronizationContext.Send(Test, null);     private void Test(object placeholder)     {         Debug.WriteLine(Thread.CurrentThread.Name);      }` Thread.CurrentThread.Name通常返回null,在其他情况下返回NewStatThread。我不想暗示这种行为是间歇性的。只是我尝试了许多不同的变体,并在不同的情况下从许多不同的位置调用了此方法

我的印象是synchronizationContext应该包含对向导线程的引用,当我调用Send方法时,回调方法应该在向导线程上执行

//Put the Wizard on a separate thread to maintain UI  //responsiveness during the export process Thread t = new Thread(LaunchBatchExportWizardView); t.SetApartmentState(ApartmentState.STA); t.Name = "WizardThread"; t.Start(); 有人能看出我的哪些假设是无效的,或者提出一个解决方案的途径吗


从概念上讲,我认为要么我必须强制我的应用程序从DoWork处理程序返回到向导线程,要么在启动DatabaseConnectivityLoss对话框之前强制它返回到向导线程。据我所知,在将匿名线程设置为STA之前,我无法访问匿名线程,而STA必须在启动之前完成

你能总结一下你的问题吗 问题?它太长了,我读不懂