Reputation: 335
I created WPF form with a "Start" button, this button is "StartMacros" function.
When i click "Start" button i want to run a loop and open a firefox browser every 10 seconds, without stopping the MAIN thread, so i can create another "Pause" button or "Cancel" button
Right now everything is working but there is no delay in the loop, how can i create it? the "await Task.Delay((10000));" is not creating the delay..
public void StartMacros(object sender, RoutedEventArgs e)
{
AsyncTimerLoop();
}
public async void AsyncTimerLoop()
{
for (int profileNumber = 1; profileNumber <= 10; profileNumber++)
{
OpenBrowser(profileNumber);
await Task.Delay((10000));
}
}
public void OpenBrowser(int profileNumber)
{
System.Diagnostics.Process.Start("firefox.exe", "-P " + profileNumber + " -no-remote imacros://run/?m=\"" + ImacroFilePath + "\"");
}
Upvotes: 0
Views: 1746
Reputation: 35318
You can accomplish this with just one method:
private async void StartMacros(object sender, RoutedEventArgs e)
{
for (int profileNumber = 1; profileNumber <= 10; profileNumber++)
{
OpenBrowser(profileNumber);
await Task.Delay(10000);
}
}
Note, I have added the async
keyword to the method.
What's going on here is subtle. The reason your code didn't work as expected was because your StartMacros
was calling your AsyncTimerLoop
method synchronously. It calls the method which then loops a bunch of times really fast on the main thread. Within each loop iteration, it calls your OpenBrowser
(still on the main thread) and then awaits a call to Task.Delay
(which actually returns an awaitable Task
, but your code doesn't do anything with that -- it just throws them away). Since you called it with the await
keyword, it does that on another thread -- one thread for each loop iteration -- and just continues looping on the main thread, calling OpenBrowser
in each loop, until it finishes the loop and exits the function; all this happens very rapidly. The calls to Task.Delay
don't do anything except delay for ten seconds on another thread and then exit. They're basically useless.
Now, you could do this:
private async void StartMacros(object sender, RoutedEventArgs e)
{
await AsyncTimerLoop();
}
public async Task AsyncTimerLoop()
{
for (int profileNumber = 1; profileNumber <= 10; profileNumber++)
{
OpenBrowser(profileNumber);
await Task.Delay((10000));
}
}
Notice here that I've added the async
keyword to StartMacros
just like in my code above, and I'm also awaiting the call to AsyncTimerLoop
. In order to do that, I had to change the return type of AsyncTimerLoop
to Task
, making it awaitable. Now when you run the code, it awaits the whole call to AsyncTimerLoop
on a separate thread, immediately returning control to to StartMacros
which exits right away so the application event loop can resume, leaving the application responsive. Meanwhile, the whole AsyncTimerLoop
task is running on a separate, single thread, waiting ten seconds during each loop iteration and therefore waiting ten seconds between each call to OpenBrowser
.
My code is similar to this modified version of yours, it's just more concise.
Upvotes: 2
Reputation: 28540
Wouldn't a timer be easier?
var timer = new Timer(o => Console.WriteLine("{0} Tick", DateTime.Now), null, 0, 6000);
Upvotes: 0
Reputation: 464
Try this code, use
var task = Task.Run(() => OpenBrowser(profileNumber));
if (task.Wait(TimeSpan.FromSeconds(10000)))
{
return task.Result;
}
Add System.Threading.Tasks namespace to your code to access Task Parallel Library.
using System.Threading.Tasks;
public void StartMacros(object sender, RoutedEventArgs e)
{
AsyncTimerLoop();
}
public async void AsyncTimerLoop()
{
for (int profileNumber = 1; profileNumber <= 10; profileNumber++)
{
var task = Task.Run(() => OpenBrowser(profileNumber));
if (task.Wait(TimeSpan.FromSeconds(10000)))
{
return task.Result;
}
}
}
public void OpenBrowser(int profileNumber)
{
System.Diagnostics.Process.Start("firefox.exe", "-P " + profileNumber + " -no-remote imacros://run/?m=\"" + ImacroFilePath + "\"");
}
Upvotes: 0