I am making a small game with an auto play feature, but the program runs too fast so the user can't see the outcome at each stage. I am using VS 2017, so I can't use async (at least from what I have read). How can I have the program wait and allow the UI to update?
I am working in a do while loop. The main chunk of the game executes, updates the UI, and then waits for the player to click a button (assuming auto play is not running), with auto play running the do while loop repeats, but after the UI updates it would wait X seconds.
Use a Timer component instead of a loop, and put the loop body in the timer's Elapsed event.
And VS2017 definitely supports async, but it wouldn't help in this case... things would still move too fast for the user.
You can use async/await to slow down the execution of event handler without having to split the logic. This is pretty simple:
async void Button_Click(object sender, RoutedEventArgs e) // wpf event handler
{
...
await Task.Delay(1000); // pause 1 second
...
while (someCondition)
{
...
await Task.Delay(1000);
...
}
}
You can read about async/await at msdn.
If you are using WPF, then you have to look into animations. They are much simpler to use to ensure smooth changes than manually changing something (position, sizes).
Usage: DelayFactory.DelayAction(500, new Action(() => { this.RunAction(); }));`
//Note Forms.Timer and Timer() have similar implementations.
//Assumes you will have a DelayFactory Static Class
public static void DelayAction(int millisecond, Action action)
{
var timer = new DispatcherTimer();
timer.Tick += delegate
{
action.Invoke();
timer.Stop();
};
timer.Interval = TimeSpan.FromMilliseconds(millisecond);
timer.Start();
}
Wait function using timers, no UI locks.
public void wait(int milliseconds)
{
System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
if (milliseconds == 0 || milliseconds < 0) return;
//Console.WriteLine("start wait timer");
timer1.Interval = milliseconds;
timer1.Enabled = true;
timer1.Start();
timer1.Tick += (s, e) =>
{
timer1.Enabled = false;
timer1.Stop();
//Console.WriteLine("stop wait timer");
};
while (timer1.Enabled)
{
Application.DoEvents();
}
}
Usage:
wait(1000); //wait one second
It looks like you have a couple of options
1.You can try Sleep -(but it may hang the UI)
int Seconds = 1;
Threading.Thread.Sleep(Seconds * 1000);
2.You can try this code:
int Seconds = 1;
Private void WaitNSeconds(int seconds)
{
if (seconds < 1) return;
DateTime _desired = DateTime.Now.AddSeconds(seconds);
while (DateTime.Now < _desired) {
System.Windows.Forms.Application.DoEvents();
}
}
3.Try to use Async and see what happens
async Task MakeDelay() {
await Task.Delay(5000);
}
private async void btnTaskDelay_Click(object sender, EventArgs e) {
await MakeDelay();
}
Related
I am trying to make a game launcher where there is a limit of 10 minutes the it should close
Problem statement : I want to load the form , user should be able to do activities and then application should close after 10 minute
when i give any kind of sleep or wait in main method, the form itself is not loading i only get the messagebox ,then the application closes.
public MainForm()
{
InitializeComponent();
MessageBox.Show("Welcome");
Task.Run(async () =>
{
await Task.Delay(60000);
}).GetAwaiter().GetResult();
MessageBox.Show("one minute left");
Task.Run(async () =>
{
await Task.Delay(60000);
}).GetAwaiter().GetResult();
MessageBox.Show("time over");
Application.Exit();
}
Use System.Windows.Forms.Timer as follows:
Timer = new System.Windows.Forms.Timer();
Timer.Interval = TIME_IN_MILLISECONDS;
Timer.Tick += Timer_Tick;
private void Timer_Tick(object sender, EventArgs e)
{
//desired behavior
}
System Timer runs async, after selected interval it triggers your method
Use Microsoft's Reactive Framework (NuGet "System.Reactive.Windows.Forms" and add using System.Reactive.Linq;) and then you can do this:
public MainForm()
{
InitializeComponent();
MessageBox.Show("Welcome");
Observable
.Timer(TimeSpan.FromMinutes(1.0))
.ObserveOn(this)
.Subscribe(x => MessageBox.Show("one minute left"));
Observable
.Timer(TimeSpan.FromMinutes(2.0))
.ObserveOn(this)
.Subscribe(x =>
{
MessageBox.Show("time over");
Application.Exit();
});
}
If you want to start a task in a fire and forget fashion there is no need to call GetAwaiter().GetResult(); because this will block the thread. So, basically, there is no point at all of all of these task that you have created. You could simply make use of the Timers. As you are using Windows Forms you can use the System.Windows.Forms.Timer or you can use System.Threading.Timer. I would use the System.Windows.Forms.Timer to implement such a behavior.
Why not just schedule task from event handler:
private async void OnApplicationStarted(object sender, RoutedEventArgs e)
{
await Task.Delay((int)TimeSpan.FromMinutes(9).TotalMilliseconds);
MessageBox.Show("1 minute left");
await Task.Delay((int)TimeSpan.FromMinutes(1).TotalMilliseconds);
MessageBox.Show("time over");
Application.Exit();
}
I'd use the Form.Load event with an async event handler. This will already show your form, so users will be able to see that the program has been started.
async void OnFormLoading(object sender, ...)
{
// Notify the operator that the form is loading:
this.ShowSplashScreen();
// start the delay, but do not wait yet
Task delayTask = Task.Delay(TimeSpan.FromSeconds(5));
// do other useful initializations, this might be shorter or longer than 5 seconds
DoOtherInitializations();
// now wait for the delay task to finish:
await delayTask;
this.HideSplashScreen();
}
Or an even nicer approach: show an startup-form which shows that you are starting, with only the possibility to cancel:
in class MainForm:
private async void OnFormLoading(object sender, ...)
{
// show an intro screen while doing initializations:
using (var startupForm = new FormStartup()
{
var dlgResult = startupForm.ShowDialog(this);
if (dlgResult == DialogResult.Cancel)
{
// operator cancelled starting up:
this.Close();
}
else
{
// continue starting up
}
}
}
}
}
class FormStartup
{
public void FormStartup() {...}
private async void OnFormLoading(object sender, ...)
{
Task delayTask = Task.Delay(TimeSpan.FromSeconds(5));
DoOtherInitializations();
await delayTask;
}
}
I'm currently making a text based game, but I need the calls to pause for a certain number of milliseconds. I'm looking for something like this:
void InitProgram()
{
WriteToText("Welcome!");
CreatePause(3000); // Pause execution HERE for 3 seconds without locking UI
WriteToText("How are you?"); // Continue
StartTutorial();
}
So like, the method will be called, do its waiting thing, and then return. And when it returns, normal execution is continued.
What can I do for this effect?
You could use a timer:
readonly Timer _timer = new Timer();
void InitProgram()
{
WriteToText("Welcome!");
_timer.Interval = 3000;
_timer.Tick += timer_Tick;
_timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
WriteToText("How are you?"); // Continue
StartTutorial();
_timer.Stop();
}
If you wanted to call this multiple times, just put _timer.Start into it's own method, every time you call it, 3 seconds later whatever is in timer_Tick will happen:
private void StartTimer()
{
_timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
WriteToText("How are you?"); // Continue
StartTutorial();
_timer.Stop();
}
If target framework is 4.0 or higher and IDE is VS2012 or higher, then you can use async/await
private async void Foo()
{
Console.WriteLine("Going to Await");
await Task.Delay(5000);
Console.WriteLine("Done with awaiting");
}
It's pretty simple and straightforward and the biggest advantage is, that your "linear" flow is kept, because the necessary callbacks etc are handled by the compiler automatically.
How about something like this?
Its all pseudo code, I have not tested...
Thread _thread;
void InitProgram()
{
WriteToText("Welcome!");
ThreadStart ts = new ThreadStart(StartThread);
_thread = new Thread(ts);
_thread.Start();
}
private void StartThread()
{
Thread.CurrentThread.Sleep(3000);
this.Invoke(delegate { this.StartTutorial(); });
}
private void StartTutorial()
{
WriteToText("How are you?"); // Continue
//Start tutorial
}
Hahahahhaha! I figured out the answer using possibly the most crazy method available! Check this out, guys!
First, declare global List:
private List<Action> actionList = new List<Action>();
Now, this is what you do in the method you wish to call wait from:
WriteToLog("Hello!");
Action act = delegate() { WriteToLog("How are you?"); }; actionList.Add(act); // Create a new Action out of this method and add it to the action list!
CreatePause(3000); // Call the method with your specified time
void CreatePause(int millisecondsToPause)
{
Action w = delegate() { Thread.Sleep(millisecondsToPause); };
for (int i = 0; i < actionList.Count; i++) // Iterate through each method in the action list that requires attention
{
Action a_Instance = (Action)actionList[i]; // Add a cast to each iteration
AsyncCallback cb = delegate(IAsyncResult ar) { Invoke(a_Instance); w.EndInvoke(ar); }; // Do each method!!!!
w.BeginInvoke(cb, null);
}
actionList.Clear(); // Clear that list!
return; // Return!
}
To be honest, this shouldn't work, but it does.
I am trying to delay my method by using a timer:
private System.Timers.Timer _delayTimer;
private void delay()
{
_delayTimer = new System.Timers.Timer();
_delayTimer.Interval = 5000;
//_delayTimer.Enabled = true;
_delayTimer.Elapsed += _delayTimer_Elapsed;
_delayTimer.Start();
someMethod();
}
}
private void _delayTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// delay for 5 seconds
}
When i am get into delay() method i want to start the timer, than i want the 5 seconds delay and only after that i want to execute someMethod() and currently this not happen, after execute delay() the someMethod() executed without 5 seconds delay
Your current code sets up the timer and then immediately executes someMethod. Instead of this, you need to put the actual method call inside your Elapsed handler:
private void delay()
{
_delayTimer = new System.Timers.Timer();
_delayTimer.Interval = 5000;
//_delayTimer.Enabled = true;
_delayTimer.Elapsed += _delayTimer_Elapsed;
_delayTimer.Start();
}
}
private void _delayTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
someMethod();
}
And if there's nothing else you intend to do you can simply write this inline:
_delayTimer = new System.Timers.Timer();
_delayTimer.Interval = 5000;
_delayTimer.Elapsed += (o, e) => someMethod();
_delayTimer.Start();
If you're in .Net4.5(or using BCL.Async pack) you can use Task.Delay
private async void delay()
{
await Task.Delay(5000);
someMethod();
}
If you're under .Net4.5
Try the below code. I'll suggest you to use System.Threading.Timer
var timer = new System.Threading.Timer(x => someMethod(), null, 5000, System.Threading.Timeout.Infinite);\
Don't forget when you use Threading.Timer someMethod will be invoked in ThreadPool thread, If you're accessing UI you need to marshal the call to UI thread.
If you want the current thread to pause for five seconds, then call Thread.Sleep. For example:
Thread.Sleep(TimeSpan.FromSeconds(5));
DoSomething();
Use a timer if you want something to happen five seconds from now, while you're doing something else. When the timer elapses, the action will be executed on a thread pool thread.
Also, if you only want the timer to execute one time (rather than once every five seconds), be sure to set AutoReset to false.
You need to call someMethod in the timer's Elapsed handler:
private void delay()
{
_delayTimer = new System.Timers.Timer();
_delayTimer.Interval = 5000;
_delayTimer.AutoReset = false; //so that it only calls the method once
_delayTimer.Elapsed += (s,args) => someMethod();
_delayTimer.Start();
}
You could also use Task.Delay instead:
private void delay()
{
Task.Delay(5000)
.ContinueWith(t => someMethod());
}
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
System.Threading.Thread.Sleep(5000);
/*
* Here Yopur code to do some method :D
* */
});
I wish my method to wait about 500 ms and then check if some flag has changed. How to complete this without blocking the rest of my application?
You can use await Task.Delay(500); without blocking the thread like Sleep does, and with a lot less code than a Timer.
Thread.Sleep(500) will force the current thread to wait 500ms. It works, but it's not what you want if your entire application is running on one thread.
In that case, you'll want to use a Timer, like so:
using System.Timers;
void Main()
{
Timer t = new Timer();
t.Interval = 500; // In milliseconds
t.AutoReset = false; // Stops it from repeating
t.Elapsed += new ElapsedEventHandler(TimerElapsed);
t.Start();
}
void TimerElapsed(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Hello, world!");
}
You can set AutoReset to true (or not set it at all) if you want the timer to repeat itself.
I don't really understand the question.
If you want to block before checking, use Thread.Sleep(500);
If you want to check asynchronously every x seconds, you can use a Timer to execute a handler every x milliseconds.
This will not block your current thread.
It the method in question is executing on a different thread than the rest of your application, then do the following:
Thread.Sleep(500);
System.Threading.Thread.Sleep(500);
Update
This won't block the rest of your application, just the thread that is running your method.
Using a timer should do the trick
if you need to use a thread then here is an example
void Main()
{
System.Threading.Thread check= new System.Threading.Thread(CheckMethod);
check.Start();
}
private void CheckMethod()
{
//Code
Thread.Sleep(500);
}
Asynchron Task:
var task = new Task (() => function_test()); task.Start();
public void function_test() { `Wait for 5000 miliseconds` Task.Delay(5000);` }
I've recently been struggling with the same issue where I needed an action to be run on schedule without blocking the UI.
Here's my solution:
private void Button_Click(object sender, RoutedEventArgs e)
{
RunOnSchedule(interval, cancellationToken);
}
private void RunOnSchedule(int interval, CancellationToken cancellationToken)
{
// Start the task you want to run on schedule
TaskToRunOnSchedule(args);
Task.Run(async () =>
{
// This loop checks if the task was requested to be cancelled every 1000 ms
for (int x = 0; x < interval; x+=1000)
{
if (cancellationToken.IsCancellationRequested)
{
break;
}
await Task.Delay(1000);
}
}).GetAwaiter().OnCompleted(() =>
{
// Once the task for delaying is completed, check once more if cancellation is requested, as you will reach this point regardless of if it was cancelled or not.
if (!cancellationToken.IsCancellationRequested)
{
// Run this method again
RunOnSchedule(interval, cancellationToken);
}
});
}
In a WinForms application, when I want to wait on the main thread without blocking the app, I usually use
private void Wait (double milliseconds)
{
DateTime next = System.DateTime.Now.AddMilliseconds(milliseconds);
while (next > System.DateTime.Now)
Application.DoEvents();
}
I would like to slow down a loop so that it loops every 5 seconds.
In ActionScript, I would use a timer and a timer complete event to do this. How would I go about it in C#?
You can add this call inside your loop:
System.Threading.Thread.Sleep(5000); // 5,000 ms
or preferable for better readability:
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
However, if your application has a user interface you should never sleep on the foreground thread (the thread that processes the applications message loop).
You can try using Timer,
using System;
public class PortChat
{
public static System.Timers.Timer _timer;
public static void Main()
{
_timer = new System.Timers.Timer();
_timer.Interval = 5000;
_timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
_timer.Enabled = true;
Console.ReadKey();
}
static void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//Do Your loop
}
}
Also if your operation in loop can last more then 5 sec, You can set
_timer.AutoReset = false;
to disable next timer tick until operation finish in loop
But then end end of loop You need again to enable timer like
_timer.Enabled = true;
Don't use a loop at all. Set up a Timer object and react to its fired event. Watch out, because these events will fire on a different thread (the timer's thread from the threadpool).
Let's say you have a for-loop that you want to use for writing to a database every second. I would then create a timer that is set to a 1000 ms interval and then use the timer the same way you would use a while-loop if you want it to act like a for-loop. By creating the integer before the loop and adding to it inside it.
public patial class Form1 : From
{
timer1.Start();
int i = 0;
int howeverLongYouWantTheLoopToLast = 10;
private void timer1_Tick(object sender, EventArgs e)
{
if (i < howeverLongYouWantTheLoopToLast)
{
writeQueryMethodThatIAssumeYouHave(APathMaybe, i); // <-- Just an example, write whatever you want to loop to do here.
i++;
}
else
{
timer1.Stop();
//Maybe add a little message here telling the user the write is done.
}
}
}