async function running in sequence WPF - c#

so I am making a small WPF app.
I am new to C# and Multithreading, I want to run certain methods in sequence but because one of the methods is Async it does not run in sequence.
private async void LoadButton_Click(object sender, RoutedEventArgs e)
{
if (!OpenFile()) return; // opens a file dialog and ensure format is correct
await Task.Run(() =>
{
// some heavy task which I run here so that I dont freeze the UI
});
}
private void TheFunctionIwantToRunInSeqeuence(object sender, RoutedEventArgs e)
{
LoadButton_Click(sender, e);
SaveCareerInfoButton_Click(sender, e); // I want this line to wait for load to finish
LoadButton_Click(sender, e);
ImportCareerInfoButton_Click(sender, e); // I want this line to wait for the second load to finish
}

Await these calls as well, refactor your code a bit.. extract handler's content to a separate method and don't pass senders and args between handlers
private Task Load()
{
if (!OpenFile()) return;
return Task.Run(() =>
{
// some heavy task which I run here so that I dont freeze the UI
});
}
private async void LoadButton_Click(object sender, RoutedEventArgs e)
{
await Load();
}
private async void TheFunctionIwantToRunInSeqeuence(object sender, RoutedEventArgs e)
{
await Load();
// refactor your code to not pass sender, e.. SaveCareer();
SaveCareerInfoButton_Click(sender, e);
await Load();
// refactor your code to not pass sender, e.. ImportCareer();
ImportCareerInfoButton_Click(sender, e);
}

You can use await to wait an async function to finish and make function TheFunctionIwantToRunInSeqeuence to async Task return type:
private async Task TheFunctionIwantToRunInSeqeuence(object sender, RoutedEventArgs e)
{
await LoadButton_Click(sender, e);
SaveCareerInfoButton_Click(sender, e); // I want this line to wait for load to finish
await LoadButton_Click(sender, e);
ImportCareerInfoButton_Click(sender, e); // I want this line to wait for the second load to finish
}

Related

Cancel button click event while executing heavy method in C#

I want to cancel button click event while executing any heavy method in C#.
Lets say there is following method and event:
private void Submit()
{
//This method requires 5 seconds and it is blocking method
}
private void button_Click(object sender, EventArgs e)
{
//Some code here
}
When I click on button while executing Submit method, the button click event does not fire, instead of it fires after completed the execution of Submit method.
I want to cancel this event when clicked while executing the Submit method.
I can not disable this button as my application contains many of such buttons.
I also want to prevent all events to be fired that is initiated during execution of Submit method if possible and allow all events to be fired after execution of Submit method.
Pls suggest any solution or workaround to achieve the about task.
If you start a new task using async, you will be able to call the cancel method whilst executing the Submit.
private async Task Submit()
{
await Task.Factory.StartNew(() =>
{
// Blocking code, network requests...
});
}
Have a look at https://msdn.microsoft.com/en-us/library/mt674882.aspx for await async reference, and also Channel 5 has some great videos about it https://channel9.msdn.com/Series/Three-Essential-Tips-for-Async
If you want to stop "Submit" whenever you trigger "Cancel", I would recommend using a CancellationEventSource to cancel the task, have a look:
using System.Threading.Tasks;
private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
private async Task Submit()
{
var cancellationToken = this.cancellationTokenSource.Token;
await Task.Factory.StartNew(() =>
{
cancellationToken .ThrowIfCancellationRequested();
// Blocking code, network requests...
}, this.cancellationTokenSource.Token);
}
private void button_Click(object sender, EventArgs e)
{
this.cancellationTokenSource.Cancel();
}
Have a look at this msdn article on CancellationTokenSource and Task https://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx
Edit 1:
I don't want to stop the Submit() any more. I want to cancel the event
during execution of Submit() and allow event to be fired after
completion of the Submit()
Create a Task and await for it to finish:
private Task submitTask;
private void Submit()
{
this.submitTask = Task.Factory.StartNew(() =>
{
// Some Code
}
}
private async void button_Click(object sender, EventArgs e)
{
// Awaiting will prevent blocking your UI
await this.submitTask;
// Some Code
}
You can use Task to achieve that.
CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
CancellationToken _ct;
private void Submit()
{
_ct = cancellationTokenSource.Token;
var task = Task.Factory.StartNew(() =>
{
_ct.ThrowIfCancellationRequested();
//your code here
}, _ct);
}
private void button_Click(object sender, EventArgs e)
{
//Some code here
_cancellationTokenSource.Cancel();
}
CancellationToken is an object that allows you to send to 'Task' information that the task should be cancelled. Additionally inside your Task make sure you are ThrowIfCancellationRequested to make sure that this task will be stopped.
In my example button_click is the cancel button.
More information you can possibly find here: https://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx
delegate void submitdelegate();
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
IAsyncResult ia;
private void Form1_Load(object sender, EventArgs e)
{
submitdelegate sd=Submit;
ia=sd.BeginInvoke(()=>{},null,null);
}
private void Submit()
{
}
void button_Click(object sender, EventArgs e)
{
if(ia.IsCompleted)
{//run all the things you want here
}
}
creating an instance in Iasyncresult will give you wether the delegate finished executioin.
http://www.dotnetcurry.com/ShowArticle.aspx?ID=634
Your goal is to prevent the button(s) from having any effect if a call to Submit() is currently active.
To do so:
(1) Wrap the call to Submit() inside an async method that calls Submit() as a separate task:
private async Task SubmitAsync()
{
await Task.Run(() => Submit());
}
(2) Add to the class a boolean field that will be used to check if Submit() is currently executing:
private bool submitIsActive = false;
(3) Change your button click handler(s) to be async and check the submitIsActive flag before awaiting SubmitAsync():
private async void button_Click(object sender, EventArgs e)
{
if (!submitIsActive)
{
submitIsActive = true;
await SubmitAsync();
submitIsActive = false;
}
}
At first glance you might think that there's a race condition where submitIsActive is set to true in one thread, but checked in a different thread. This is not so because the button_Click() method will only ever be called from the UI thread.
Also note that this approach does NOT allow you to cancel a call to Submit() - but I don't think you were asking for that.
What about unsubscribing the buttons from their click events for the duration of the Submit() method? Too many buttons?

Stop Task when task run [duplicate]

This question already has an answer here:
Async/await for long-running API methods with progress/cancelation
(1 answer)
Closed 6 years ago.
How can i totally stop a task when task running?
private async void button1_Click(object sender, EventArgs e)
{
await Backup(file);
}
public async Task Backup(string File)
{
await Task.Run(() =>
{
1)do something here
2)do something here
3)do something here
});
}
private async void button2_Click(object sender, EventArgs e)
{
<stop backup>
}
If say i want to stop task during 2nd thing is processing, and i click a button2 then the task will stop process
How do I cancel or end the task from button2_Click?
// Define the cancellation token source & token as global objects
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token;
//when button is clicked, call method to run task & include the cancellation token
private async void button1_Click(object sender, EventArgs e)
{
token = source.Token;
await Backup(file, token);
}
public async Task Backup(string File, CancellationToken token)
{
Task t1 = Task.Run(() =>
{
//do something here
},
token);
}
//cancel button click event handler
private async void cancelButton_Click(object sender, EventArgs e)
{
if(source != null)
{
source.Cancel();
}
}
//tasks
https://msdn.microsoft.com/en-us/library/system.threading.tasks.task(v=vs.110).aspx
//CancellationToken
https://msdn.microsoft.com/en-us/library/system.threading.cancellationtoken(v=vs.110).aspx

This delegate does not work

I need to add an element to a Winform ListView control from other thread, so I am using a delegate, this way:
private delegate void AddMessageLogCallback(string message);
public void AddMessageLog(string message)
{
if (InvokeRequired)
Invoke(new AddMessageLogCallback(AddMessageLog), message);
else
{
lstLogs.Items.Add(message).EnsureVisible();
}
}
The problem is that the Invoke does nothing, not even throws an exception.
I have used this kind of delegates before and never had problems. What different is at this time?
Your code works as desired with the test code below, so the problem should be something else.
private void button1_Click(object sender, EventArgs e)
{
AddMessageLog("local message");
}
private async void button2_Click(object sender, EventArgs e)
{
await Task.Run(() => AddMessageLog("async message"));
}
Btw, I would mention that there is no need to define a new AddMessageLogCallback delegate and to call the AddMessageLog recursively. So a more simple (and maybe cleaner) solution:
public void AddMessageLog(string message)
{
Action addLog = () => lstLogs.Items.Add(message).EnsureVisible();
if (InvokeRequired)
Invoke(addLog);
else
addLog();
}

Windows form breaks when calling Task.Result

I have code similar to following inside my Windows form:
private async Task<string> GetGreetingAsync()
{
return await Task.Run(() => "Hello");
}
private void button1_Click(object sender, EventArgs e)
{
var x = GetGreetingAsync().Result;
}
Clicking the button causes the entire Windows form to freeze and become unresponsive. No exception is thrown.
Even when I don't use the task .Result directly in the event handler and the whole async marked code is in some class library function, which provides interface without async, the problem still occurs. Unit tests for such class library pass without any problems, but when I call its function from event handler on Windows form, it breaks and does not respond.
Why does this happen? How can I fix it?
You are blocking the the UI thread with .Result; (see ConfigureAwait)
private async Task<string> GetGreetingAsync()
{
return await Task.Run(() => "Hello").ConfigureAwait(false);
}
private void button1_Click(object sender, EventArgs e)
{
var x = GetGreetingAsync().Result;
}
Or go all the way async
private async Task<string> GetGreetingAsync()
{
return await Task.Run(() => "Hello");
}
async private void button1_Click(object sender, EventArgs e)
{
var x = await GetGreetingAsync();
}
Using this version you don't even need to await in GetGreetingAsync
private Task<string> GetGreetingAsync()
{
return Task.Run(() => "Hello");
}
async private void button1_Click(object sender, EventArgs e)
{
var x = await GetGreetingAsync();
}
You should be using await instead of Result on a Task<T> to get non-blocking behavior.
private async void button1_Click(object sender, EventArgs e)
{
var x = await GetGreetingAsync();
}
Calling Result causes the code to wait until the Task has completed where calling await allows the async behavior to be used.
Edit
Actually looking at your code again if you're doing
private async Task<string> GetGreetingAsync()
{
return await new Task<string>(() => "Hello");
}
That is really not needed. That block can just be
private Task<string> GetGreetingAsync()
{
return new Task<string>(() => "Hello");
}
There's no need for the thing returning the task to be async.

Stopping Threading

I am new to winforms programming and I am starting to work with threads.
I have managed to start a thread, but now I want to be able to click on a cancel button to stop the thread.
Here is my code so far...
This starts the thread:
private void btnSessions_Click(object sender, EventArgs e)
{
Thread downloadThread = new Thread(new ThreadStart(DownloadThread));
downloadThread.Start();
}
This is the thread:
void DownloadThread()
{
// Do the work
}
This is the button I want to use to cancel the thread:
private void btnCancel_Click(object sender, EventArgs e)
{
// Stop the thread
}
Can anyone help me work out what I need to put in btnCancel_Click please?
You should use the Task Parallel Library (TPL) for this, which supports a natural way of canceling tasks:
private CancellationTokenSource _tokenSource2;
private CancellationToken _token;
private void btnSessions_Click(object sender, EventArgs e)
{
_tokenSource2 = new CancellationTokenSource();
_token = _tokenSource2.Token;
Task task = Task.Run(() => DownloadThread(), _token);
}
private void DownloadThread()
{
while (true)
{
//do work
//cancel if needed
if (_token.IsCancellationRequested)
{
_token.ThrowIfCancellationRequested();
}
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
// Stop the thread
_tokenSource2.Cancel();
}
More about canceling tasks: http://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx
Why you should not use Thread.Abort: What's wrong with using Thread.Abort()
You need to make the downloadThread a field in your object:
Thread downloadThread;
private void btnSessions_Click(object sender, EventArgs e)
{
downloadThread = new Thread(new ThreadStart(DownloadThread));
downloadThread.Start();
}
void DownloadThread()
{
// Do the work
}
private void btnCancel_Click(object sender, EventArgs e)
{
downloadThread.Abort();
}
A background worker would be a better solution for ui related processing.
It's better don't use Thread and especially Thread.Abort for task like this. C# has high abstract wrapper to hide threads. Just use Task and CancellationToken.
Here is example:
var cts = new CancellationTokenSource(); // define in class
CancellationToken ct = cts.Token;
private void btnSessions_Click(object sender, EventArgs e)
{
Task.Factory.StartNew(() => DownloadThread(), ct ); // start task
}
private void DownloadThread()
{
// You need to check this at some point where cancel may occur
if (ct.IsCancellationRequested)
ct.ThrowIfCancellationRequested();
}
private void btnCancel_Click(object sender, EventArgs e)
{
cancelToken.Cancel(false); // cancel task
}
More information can be found at msdn

Categories

Resources