Reputation: 894
I'm trying to create a realistic console type game with C#, and what I need it to do is append text like this:
hi
hello
awesome
nice
but instead of it going ALL at once, I want it to do this:
hi
(2 second pause)
hello
(4 second pause)
awesome
(1 second pause)
nice
I have tried this:
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;
}
And then I can call it like this Invoke(new _pause(pause),3);
but that basically freezes the thread! So it pastes all at once anyway, just a delay before
the montage of paste!
How can I do a smooth delay type system like I have described?
Upvotes: 2
Views: 1381
Reputation: 48066
You should avoid busy-waiting and instead use a timer such as Task.Delay
.
One possible way of doing that is by leveraging C# 4.5's new async feature:
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");
}
By using the async syntax you are instructing the machine to run your code interleaved with other code - so that it can still do screen updates in the meantime, for instance. It automatically returns to the same SynchronizationContext, so in your case since you started on the GUI thread, you'll stay on it; this is important since only that thread may alter your text-box.
To summarize why you want to do it similar to this like this:
If you need to support .NET 2.0, you may want to look at the windows forms Timer
. In short, this exposes event handlers you can hook which fire after a delay. However, as the example on the MSDN page illustrates, it's not as easy to use and will take much more manual orchestration.
Additionally, you could use a thread. If you do so, you are responsible for ensuring thread safety: you may NOT execute txtInput.Append
on any thread other than the GUI thread:
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); }
This model is almost as simple as the async model. Two pitfalls are that you should avoid busy waiting (use Thread.Sleep) and that you must make sure you properly use BeginInvoke
for all UI-affecting code. It's possibly even slightly faster than async
. However, threads have a fairly large overhead (mostly in terms of memory), so this solution won't scale to large amounts of delayed interaction.
async
if you can.Timer
, which is a hassle.Upvotes: 3
Reputation: 894
I fixed this issue via this method: Pause execution of a method without locking GUI. C#
It can be easily fixed by running the pause on a seperate thread, therefore not locking the UI. Thanks for everyone's help!
Upvotes: 0