C# 运行异步任务并调用winform控件

C# 运行异步任务并调用winform控件,c#,winforms,asynchronous,task,C#,Winforms,Asynchronous,Task,如果您有此代码: Task[] tasks = new Task[3]; int index = 0; foreach (KeyValuePair<string, int> packageId in PackageIds) { await Task.Run(() => _logger.Log(packageId.Key)); tasks[index] = Task.Factory.StartNew(() => { Log(pa

如果您有此代码:

Task[] tasks = new Task[3];


int index = 0;
foreach (KeyValuePair<string, int> packageId in PackageIds)
{
    await Task.Run(() => _logger.Log(packageId.Key));

    tasks[index] = Task.Factory.StartNew(() =>
    {
        Log(packageId.Key);
    });
    index++;
}

Task.WaitAll(tasks);
_logger.Log("all done");
当我运行它时,我可以看到代码试图调用listView1。但在那之后,应用程序将挂起,根本无法继续。当我删除Log()并再次运行它时,它工作得非常好


如何在日志记录中运行此代码?

您正在以一种危险的方式使用InvokeRequiered/Invoke模式

问题是您使用
invokererequired
检查线程是否可以从ListView1调用函数。如果不是,则不使用Invoke调用ListView1函数,而是调用自己的函数(this.Log)

实现此模式的正确方法是检查您自己的表单是否需要调用。询问:this.InvokeRequired而不是listview1.InvokeRequired:

class MyForm : Form
{
    ...

    private void MyEventHandler(object sender, ...)
    {
        if (this.InvokeRequired)
        {
            Invoke(new MethodInvoker( () => this.MyEventHandler(sender, ...));
        }
    }
    else
    {
        ProcessMyEvent(...);
    }
如果使用调试器单步执行此函数,您将看到需要调用,因此再次调用同一函数,之后不再需要调用


顺便说一句,使用
MethodInvoker
而不是
Action
的原因在中给出,您正在以危险的方式使用InvokeRequiered/Invoke模式

问题是您使用
invokererequired
检查线程是否可以从ListView1调用函数。如果不是,则不使用Invoke调用ListView1函数,而是调用自己的函数(this.Log)

实现此模式的正确方法是检查您自己的表单是否需要调用。询问:this.InvokeRequired而不是listview1.InvokeRequired:

class MyForm : Form
{
    ...

    private void MyEventHandler(object sender, ...)
    {
        if (this.InvokeRequired)
        {
            Invoke(new MethodInvoker( () => this.MyEventHandler(sender, ...));
        }
    }
    else
    {
        ProcessMyEvent(...);
    }
如果使用调试器单步执行此函数,您将看到需要调用,因此再次调用同一函数,之后不再需要调用


顺便说一句,使用
MethodInvoker
而不是
Action
的原因在

中给出。显然,您有无限循环/递归-
Log
函数将永远调用自己,以防
listView1.InvokeRequired=true
如何使用日志运行此代码?-您试图通过记录来自另一个线程的消息来实现什么?为什么不在等待后在listview的
foreach
循环中简单地添加日志消息呢?现在的代码完全没有理由使用任务。所有的事情都是在UI线程上完成的。如果没有一个好的线程,就不可能知道如何最好地处理您的场景。也就是说,你发布的代码是各种各样的错误。最大的问题(很可能是挂起的原因)是您调用了
Task.WaitAll()
,而(显然)在其他线程中执行的代码最终会希望调用
Control.Invoke()
,并使用正在阻塞的线程。除此之外,还不清楚你为什么要费心处理
任务
之类的事情。这似乎没有什么好处,只会让你感到困惑。很明显,你有无限循环/递归-
Log
函数将永远调用自己,以防
listView1.invokererequired=true
如何使用日志运行此代码?-您试图通过记录来自另一个线程的消息来实现什么?为什么不在等待后在listview的
foreach
循环中简单地添加日志消息呢?现在的代码完全没有理由使用任务。所有的事情都是在UI线程上完成的。如果没有一个好的线程,就不可能知道如何最好地处理您的场景。也就是说,你发布的代码是各种各样的错误。最大的问题(很可能是挂起的原因)是您调用了
Task.WaitAll()
,而(显然)在其他线程中执行的代码最终会希望调用
Control.Invoke()
,并使用正在阻塞的线程。除此之外,还不清楚你为什么要费心处理
任务
之类的事情。这似乎没有什么好处,只会让你感到困惑。