[英]C# - Cross Thread Error using Async and Await on TextBox
我是 Async 和 Await 的新手,并创建了一个简单的项目来了解它是如何工作的。 为此,我有一个简单的 Windows 窗体应用程序,它有 2 个元素:
当我单击按钮时,它应该在 TextBox 中显示所有已完成的项目。 这是我写的代码:
private async void btnGetCompletedItems_Click(object sender, EventArgs e)
{
QueueSystem queueSystem = QueueSystem.NewInstance(75);
Stopwatch watch = new Stopwatch();
watch.Start();
await Task.Run(() => GetCompletedItems(queueSystem));
watch.Stop();
lblTime.Text = $"{watch.ElapsedMilliseconds.ToString()} ms";
}
private void GetCompletedItems(QueueSystem queueSystem)
{
foreach (var item in queueSystem.GetCompletedItems())
{
txtItems.Text += $"{txtItems.Text}{item.ItemKey}{Environment.NewLine}";
}
}
但是,我收到一个错误
txtItems.Text += $"{txtItems.Text}{item.ItemKey}{Environment.NewLine}";
错误说
附加信息:跨线程操作无效:控制从创建它的线程以外的线程访问的“txtItems”。
我检查了 Debug 并为 GetCompletedItems() 创建了一个新线程。 当我读到 Async 和 Await 时,我读到它不一定创建一个新线程,但它似乎出于某种原因创建了一个新线程。
我对 Async 和 Await 的实现和理解是错误的吗? 是否可以在 Windows 窗体应用程序中使用 Async 和 Await?
您无法访问不同线程上的 UI 线程。 这应该有帮助
private async void btnGetCompletedItems_Click(object sender, EventArgs e)
{
QueueSystem queueSystem = QueueSystem.NewInstance(75);
Stopwatch watch = new Stopwatch();
watch.Start();
var results = await Task.Run(() => queueSystem.GetCompletedItems());
foreach (var item in results)
{
txtItems.Text += $"{txtItems.Text}{item.ItemKey}{Environment.NewLine}";
}
watch.Stop();
lblTime.Text = $"{watch.ElapsedMilliseconds.ToString()} ms";
}
当我读到 Async 和 Await 时,我读到它不一定会创建一个新线程
对于常规异步方法来说,这是正确的。 考虑一下:
private async void button1_Click(object sender, EventArgs e)
{
Trace.WriteLine(Thread.CurrentThread.ManagedThreadId);
await DoesNothing();
}
private async Task DoesNothing()
{
// outputs the same thread id as similar line as from above;
// in particlar, for WinForms this means, that at this point
// we are still at UI thread
Trace.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1);
}
但它似乎出于某种原因创造了一个新的
这就是Task.Run
的用途:
将指定的工作排入队列以在 ThreadPool 上运行
换句话说,它将您作为委托传递给线程池线程的任何内容推送。 由于我们在 WinForms 中,这意味着匿名方法() => GetCompletedItems(queueSystem)
将在线程池线程中执行,而不是在 UI 线程中执行。
这是上面的代码示例,几乎没有变化:
private async void button1_Click(object sender, EventArgs e)
{
Trace.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Run(DoesNothing);
}
private async Task DoesNothing()
{
// outputs DIFFERENT thread id;
// in particlar, for WinForms this means, that at this point
// we are not at UI thread, and we CANNOT access controls directly
Trace.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1);
}
您可以通过以下方式从另一个线程访问该线程。 它确实有助于避免应用程序中的跨线程异常。
private void Thread()
{
this.Invoke((System.Action)(() => {
//your thread call or definition
});
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.