Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.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# 如何在目标线程上运行事件处理程序_C#_Multithreading_Winforms_Events - Fatal编程技术网

C# 如何在目标线程上运行事件处理程序

C# 如何在目标线程上运行事件处理程序,c#,multithreading,winforms,events,C#,Multithreading,Winforms,Events,给出C#代码示例: using System; using System.Threading; using System.Windows.Forms; public class MnFrm : Form { private void MnFrm_Load(Object sender, EventArgs e) { this.WorkCompleted += MnFrm_WorkCompleted; } private void btn_Click(Obje

给出C#代码示例:

using System;
using System.Threading;
using System.Windows.Forms;

public class MnFrm : Form
{
   private void MnFrm_Load(Object sender, EventArgs e)
   {
      this.WorkCompleted += MnFrm_WorkCompleted;
   }

   private void btn_Click(Object sender, EventArgs e)
   {
      ThreadPool.QueueUserWorkItem(AsyncMethod);
   }

   private void MnFrm_WorkCompleted(Object sender, Boolean e)
   {
      MessageBox.Show("Work completed");
   }

   private void AsyncMethod(Object state)
   {
      // Do stuff
      Boolean result = true; // just as an example
      WorkCompleted?.Invoke(this, result);
   }

   private event EventHandler<Boolean> WorkCompleted;
}
使用系统;
使用系统线程;
使用System.Windows.Forms;
公共类MnFrm:表格
{
私有void MnFrm_加载(对象发送方,事件参数e)
{
this.WorkCompleted+=MnFrm_WorkCompleted;
}
私有无效btn_单击(对象发送者,事件参数e)
{
QueueUserWorkItem(异步方法);
}
私有void MnFrm_工作已完成(对象发送方,布尔值e)
{
MessageBox.Show(“工作完成”);
}
私有void异步方法(对象状态)
{
//做事
Boolean result=true;//仅作为示例
工作完成?调用(此,结果);
}
私有事件EventHandler工作已完成;
}
当用户单击按钮
btn
时,将在线程池管理的另一个线程上执行方法
AsyncMethod
。一段时间后,工作完成,结果通过另一个事件发回。 此事件处理程序(
WorkCompleted
)在用于运行
asynchmethod
的线程上执行,因为执行应用程序时会出现“交叉线程”异常


因此,问题是如何在UI线程上运行事件处理程序
MnFrm\u WorkCompleted

,如果将其更改为:

this.Invoke(new Action(() =>
{
    WorkCompleted?.Invoke(this, result);
});
它会起作用的。这是因为表单包含一个方法
Invoke()
,该方法将在创建它的线程上调用该方法。事件的调用只不过是调用委托

阅读表格moet信息

您可以使用
invokererequired
来确定您的线程是否正确,但我认为这会增加开销,并降低可读性。始终使用
此选项。调用


BeginInvoke
,这在将消息“发布”到UI线程时非常有用。唯一的问题是,当线程引发许多事件而UI线程没有足够的时间处理它们时,您无法看到有多少事件排队



第三种方法是使用队列。当事件发生时,将消息添加到队列(我将使用
列表
),并使用表单计时器处理队列。其优点是,UI线程不会暂停线程,而是在将其添加到队列后直接继续。您的应用程序将被暂停。

您可以使用Control.Invoke或Control.BeginInvoke方法来调用UI线程上的特定方法。 请尝试以下代码:

private void MnFrm_WorkCompleted(Object sender, Boolean e)
{
    if (InvokeRequired)
    {
       Invoke((Action) (() => MnFrm_WorkCompleted(sender, e)));
       return;
    }
    MessageBox.Show("Work completed");
}
有关Invoke和BeginInvoke之间的差异: 谢谢大家

Jeroen van Langen的回答非常正确!成功了。事实上,我是这样做的,但为了防止偏见,我不想发布解决方案——我想看到其他解决方案


但是,我更喜欢Panagiotis Kanavos的答案,他建议使用
var result=wait Task.Run(…)
。这完美地清除了代码!谢谢你卡纳沃斯松鸡

正确的解决方案将取决于
AsyncMethod
实际执行的操作。如果方法访问某些外部资源,则可以将代码更改为在一个线程上有效运行,而不必担心线程/调用和其他多线程相关问题。为什么要使用
QueueUserWorkItem
而不是
var result=wait Task.run(…)
?它在所有受支持的.NET版本中都可用,并将所有这些代码转换为正确处理异步操作的单行代码。最早支持的.NET版本是4.5.2<代码>等待
是在4.5中添加的。4.0中的任务即使您需要从其他线程报告某些内容,也不要使用事件。这就是IProgress接口和
progress
类的工作