应该做什么
我正在尝试将一些char的文本字符写入TextBlock
。我正在使用此代码:
void WriteTextCharForChar(String text)
{
new Thread(() =>
{
foreach(Char c in text)
{
TxtDisplayAppendText(c.ToString());
Thread.Sleep(rnd.Next(20, 100));
}
Thread.CurrentThread.Abort();
}).Start();
}
问题
问题是,当多次调用此方法时,文本会变得混杂。我需要的是一种队列或等待任何方式,直到当前文本写入TextBlock
。
诅咒我对任何其他解决方案持开放态度。谢谢!
答案 0 :(得分:2)
所以这里有几个选项。
你可以在线程的工作周围添加lock
,这样一次就不会有多个运行。
但这有几个问题:
您可以创建一个线程安全队列(BlockingCollection
最好),然后从中读取一个线程并在UI线程添加到队列时写出结果
这也有问题。最值得注意的是,你正在创建一个基本上所有时间都在等待的新线程。这可能比#1好,但不是很多。
您可以完全避免使用多个线程并以异步方式执行所有操作。任务并行库为您提供了许多工具来帮助解决这个问题。这是最好的选择,因为它会导致创建0个额外的线程。
首先,我们将创建一个辅助方法来处理文本本身的写入,以便另一个线程可以处理这些调用的“调度”。使用await
编写此方法会更容易。需要注意的一个要点是,不是在未知的时间段内阻塞当前线程,而是使用Task.Delay
在将来的某个时刻继续执行而不会阻塞线程:
private async Task WriteText(string text)
{
foreach (char c in text)
{
TxtDisplayAppendText(c.ToString());
await Task.Delay(rnd.Next(20, 100));
}
}
现在为您的方法。我们可以管理我们的队列,但实际上是一个链接的任务列表。如果我们有一个类型Task
的单个字段代表“上一个任务”,我们可以让每个方法调用为该任务添加一个延续,然后将自己设置为前一个任务。下一个任务将自己设置为继续,等等。每个继续将在前一个任务运行时触发,或者如果前一个任务已经完成则立即运行,因此这有效地为我们提供了“队列”。请注意,由于从UI线程调用了WriteTextCharForChar
,因此这些调用都已经同步,因此无需lock
围绕此任务的操作。
private Task previousWrite = Task.FromResult(false); //already completed task
private void WriteTextCharForChar(String text)
{
previousWrite = previousWrite.ContinueWith(t => WriteText(text))
.Unwrap();
}