您应该避免忙于等待,而应使用计时器,例如Task.Delay
.
一种可能的方法是利用 C# 4.5 的新异步功能:
async void converse() {
txtInput.Text = "hi\n";
await Task.Delay(2000);
txtInput.Append("hello\n");
await Task.Delay(4000);
txtInput.Append("awesome\n");
await Task.Delay(1000);
txtInput.Append("nice\n");
}
通过使用异步语法,您可以指示机器与其他代码交错运行您的代码 - 例如,它仍然可以同时进行屏幕更新。它会自动返回到相同的 SynchronizationContext,因此在您的情况下,自从您在 GUI 线程上启动以来,您将继续使用它;这很重要,因为只有该线程可能会更改您的文本框。
总结一下为什么要这样做类似于这样:
- 您可以避免占用 CPU 的时间忙于等待浪费能源的事情。
- 您避免阻塞 GUI 线程,以便您的更新按时出现(例如,与 CPU 占用不同,与 Thread.Sleep 不同)
- 您不需要特别担心线程调度,因为异步功能会为您做到这一点。
如果您需要支持 .NET 2.0,您可能需要查看 windows forms Timer
。简而言之,这暴露了您可以挂钩的事件处理程序,该处理程序会在延迟后触发。但是,正如 MSDN 页面上的示例所示,它并不容易使用,并且需要更多的手动编排。
此外,您可以使用线程。如果这样做,您有责任确保线程安全:您不得txtInput.Append
在除 GUI 线程之外的任何线程上执行:
void startConversation() {
(new Thread(converse) {IsBackground = true}).Start();
}
void converse() { //called a different thread
UI(() => txtInput.Text = "hi\n");
Thread.Sleep(2000);
UI(() => txtInput.Append("hello\n"));
Thread.Sleep(4000);
UI(() => txtInput.Append("awesome\n"));
Thread.Sleep(1000);
UI(() => txtInput.Append("nice\n"));
}
void UI(Action action) { this.BeginInvoke(action); }
这个模型几乎和异步模型一样简单。两个陷阱是您应该避免忙等待(使用 Thread.Sleep),并且您必须确保正确使用BeginInvoke
所有影响 UI 的代码。它甚至可能比async
. 然而,线程有相当大的开销(主要是在内存方面),所以这个解决方案不会扩展到大量的延迟交互。
概括
async
如果可以,请使用。
- 或者,使用 windows forms
Timer
,这很麻烦。
- 或者使用后台线程 - 但要注意扩展问题和忙于等待。