如果有这段代码:
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");
这是日志功能:
private void Log(string message)
{
ListViewItem lv = new ListViewItem
{
Text = $"{DateTime.Now:dd-MM-yyyy hh:mm:ss}"
};
lv.SubItems.Add(message);
if (listView1.InvokeRequired)
Invoke(new Action(() => Log(message)));
else
listView1.Items.Add(lv);
}
当我运行它时,我可以看到代码试图调用listView1。但在那之后,应用程序挂起并且根本不会继续。当我删除Log()并再次运行它时,它可以很好地工作。
如何使用日志记录运行此代码?
答案 0 :(得分:1)
您正在以危险的方式使用InvokeRequiered / Invoke模式。
问题是您使用InvokeRequired
检查您的线程是否可以从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(...);
}
如果您使用调试器来逐步执行此函数,您将看到需要调用,因此您再次调用相同的函数,之后不再需要调用。
顺便说一下,StackOverFlow: MethodInvoker vs Action for Control.BeginInvoke
中提供了使用MethodInvoker
代替Action
的原因