我正在尝试使用 C# 创建一个逼真的控制台类型游戏,我需要它做的是附加如下文本:
hi
hello
awesome
nice
但我希望它这样做:
hi
(2 second pause)
hello
(4 second pause)
awesome
(1 second pause)
nice
我已经尝试过这个:
delegate void _pause(int time);
void pause(int time)
{
if (txtInput.Text != "")
{
txtInput.Clear();
}
Stopwatch s = new Stopwatch();
s.Start();
while (s.Elapsed < TimeSpan.FromSeconds(time))
{
}
s.Stop();
return;
}
然后我可以这样调用它 Invoke(new _pause(pause),3);
但这基本上会卡住线程!所以无论如何它都会立即粘贴,只是之前有延迟
粘贴的蒙太奇!
我怎样才能做一个像我所描述的平滑的延迟类型系统?
最佳答案
您应该避免忙等待,而应使用计时器,例如 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 窗体 Timer
。简而言之,这公开了您可以在延迟后触发的事件处理程序。然而,正如 MSDN 页面上的示例所示,它并不那么容易使用,并且需要更多的手动编排。
此外,您可以使用线程。如果这样做,您有责任确保线程安全:您不能在 GUI 线程以外的任何线程上执行 txtInput.Append:
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),并且必须确保对所有影响 UI 的代码正确使用 BeginInvoke
。它甚至可能比async
稍快。但是,线程具有相当大的开销(主要是在内存方面),因此该解决方案无法扩展到大量延迟交互。
摘要
- 如果可以的话,使用
异步
。 - 或者,使用 Windows 窗体
Timer
,这很麻烦。 - 或者使用后台线程 - 但要注意扩展问题和忙于等待。
关于c# - 使用 RichTextBox 在文本追加中创建延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14998679/