2

我正在尝试使用 C# 创建一个逼真的控制台类型游戏,我需要它做的是附加这样的文本:

你好
你好
棒棒

但不是一次全部完成,我希望它这样做:


(暂停 2 秒)
你好
(暂停 4 秒)
很棒
(暂停 1 秒)
很好

我试过这个:

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);但这基本上会冻结线程!所以无论如何它都会一次粘贴,只是粘贴蒙太奇之前的延迟!

我怎样才能像我描述的那样做一个平滑的延迟类型系统?

4

2 回答 2

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 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,这很麻烦。
  • 或者使用后台线程 - 但要注意扩展问题和忙于等待。
于 2013-02-21T09:31:32.457 回答
0

我通过这种方法解决了这个问题: 暂停执行方法而不锁定 GUI。C#

它可以通过在单独的线程上运行暂停来轻松修复,因此不会锁定 UI。感谢大家的帮助!

于 2013-02-21T10:00:27.017 回答