My window doesnt remain active after i click on "async" method button - c#

i have the following code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
this.Background = Brushes.Red;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
int res = WaitFiveSecMethod();
this.text2.Text = res.ToString();
}
private int WaitFiveSecMethod()
{
Thread.Sleep(5000);
return 5;
}
private async void Button_Click_3(object sender, RoutedEventArgs e)
{
var res = await WaitFiveSecMethodAsync();
this.text1.Text = res;
}
private async Task<string> WaitFiveSecMethodAsync()
{
Thread.Sleep(5000);
return "5";
}
}
I want to show the difference between clicking the "sync" button (button 2) and clicking the "async" button (button 3). clicking both buttons should do the same time-consuming calculations (in my case represented with "Thread.Sleep(5000)").
Currently using async and wait make my client stuck i thought these keywords shouldn't block my client thread.
what am i doing wrong?

Your code below works synchronously and block UI, not async:
private async Task<string> WaitFiveSecMethodAsync()
{
Thread.Sleep(5000);
return "5";
}
Remember async has just responsibility to enable await keyword, if you don't have await, async is meaningless and turn to synchronous. So, async method must have at least one await keyword inside.
The better way is, you should delay by awaiting Task.Delay which does not block your UI thread:
private async Task<string> WaitFiveSecMethodAsync()
{
await Task.Delay(5000);
return "5";
}

Related

C# Task completion callback an exceptions

I have a WindowsForms application that I would like to be able to leverage async Task. There are a couple of issues that I'm having:
How do you handle ContinueWith so you can run continuation in the form?
What if the Form can be closed before the Task completes?
private void buttonGo_Click(object sender, EventArgs e)
{
val t = RunSomethingAsync().ContinueWith( p => { OnRunDone(); });
}
private void OnRunDone()
{
Invoke( p => { button.Enabled = true; });
}
Is the above code the right way to do this?
What happens in the above code if the Form is closed before the Task completes?
What if the RunSomethingAsync throws an uncaught exception?
I think I figured it out. I just didn't quite understand how await/async works. The solution is:
private async void buttonGo_Click(object sender, EventArgs e)
{
await RunSomethingAsync();
OnTaskComplete();
}
private void OnTaskComplete()
{
label1.Text = "Done";
}
private async Task RunSomethingAsync()
{
await Task.Delay(1000);
}

Delay a loop in timer

I am using a loop in a timer and trying to add the delay in it.But it not working
.And I don't want to use Thread.sleep() because my UI will freeze
My code :
private void Button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void Timer1_Tick(object sender, EventArgs e)
{
DoStuff();
}
private void DoStuff()
{
foreach (ListViewItem item in ListView1.Items)
{
if(item.subitem[1].Text == 0)
{
MessageBox.Show("Hello")
//Trying to add the delay here!!
}
}
}
I am trying to use private async void DoStuff()
and add await Task.Delay(milliseconds); to the loop too.But its not working because Timer1 will call DoStuff every Tick by ignoring the delay.(Tested Already)
The test code (Not Working) :
private void Button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void Timer1_Tick(object sender, EventArgs e)
{
DoStuff();
}
private async void DoStuff()
{
foreach (ListViewItem item in ListView1.Items)
{
if(item.subitem[1].Text == 0)
{
MessageBox.Show("Hello")
await Task.Delay(1000);
}
}
}
My question is how can I add the delay in this loop by not moving all DoStuff Code to be in timer (Just add the delay by not changing the code position).
As I wrote. You need to define your methods as tasks. The button code has a Task called DoStuff1. Also that means the button has to do be defined as async. Bascailly your entire issue is asynchronous programming(google that - there are many good examples out there). This way your UI wont freeze. And you can still use other buttons or texts in the UI.
public partial class Form1 : Form
{
List<string> strings = new List<String>() { "Hello", "world", "!" };
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
string returnString = await DoStuff1();
}
private async Task<string> DoStuff1()
{
foreach (string s in strings)
{
MessageBox.Show(s);
await Task.Yield();
await Task.Delay(1000);
}
return "ASYNC DONE";
}
}
[EDIT]Like this?
public partial class Form1 : Form
{
System.Timers.Timer t = new System.Timers.Timer(1000);
List<string> strings = new List<String>() { "Hello", "world", "!" };
public Form1()
{
InitializeComponent();
}
private async void button1_Click_1(object sender, EventArgs e)
{
System.Timers.Timer t = new System.Timers.Timer(1000);
t.Elapsed += async (s, ev) => await DoStuff1();
t.Start();
//t.Stop(); //Stop immediately after and then you can add delays in DoStuff1() if you want to.
}
private async Task<string> DoStuff1()
{
foreach (string s in strings)
{
MessageBox.Show(s);
}
return "ASYNC DONE";
}
}

Implement asnyc method inside a Thread

I'm working on Xamarin Forms project in Visual Studio 2017 . I need to implement async method inside thread .
Event which starting the thread
public void btnAction_Click(object sender, System.EventArgs e)
{
var load = new System.Threading.Thread((t) =>
{
ShowWarning();
});
load.Start(btnText);
}
async method should implement inside the thread
private async void ShowWarning()
{
bool response = await DisplayAlert("Warning", "Please Enter
The Key","Yes","No");
}
If DisplayAlert is truely asynchronous, why do you start a thread at all? You can declare your event handler async and simply awiat ShowWarning:
public async void btnAction_Click(object sender, System.EventArgs e)
{
await ShowWarning();
}
You might want to disable btnAction before the await and re-enable it after the await again, so you avoid another click event while awaiting.
And note that it's bad practice to declare ShowWarning as async void. It should be
private async Task ShowWarning()
{ ... }
(In case of the button event handler it's ok to return async void because otherwise you couldn't assign it to an event).
If you really need to run ShowWarning on a different thread, you can use Task.Run():
public async void btnAction_Click(object sender, System.EventArgs e)
{
await Task.Run(ShowWarning);
}

SemaphoreSlim and async/await

This works:
int _counter;
readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
async void Button_Click(object sender, RoutedEventArgs e)
{
if (_semaphore.Wait(0))
{
Title = $"{ ++_counter}";
await Task.Delay(1000); // simulate work
Title = $"{ --_counter}";
_semaphore.Release();
}
}
After first click further buttons clicks are ignored until work is finished. Tittle can be 1 or 0.
And this doesn't work
void Button_Click(object sender, RoutedEventArgs e)
{
if (_semaphore.Wait(0))
{
Test(); // moving code into separate method
_semaphore.Release();
}
}
async void Test()
{
Title = $"{ ++_counter}";
await Task.Delay(1000); // simulate work
Title = $"{ --_counter}";
}
Clicking button continuously will rise Tittle to 2, 3, and so on.
What am I doing wrong?
async void only makes sense in event handlers. It is a special type of asynchronism. It means "fire and forget".
You don't want to fire and forget the Test() method. You want to wait for it to return.
Change your Test signature to:
// Note that it returns a "Task". A task is an awaitable promise.
async Task Test()
{
//...
}
And then await it on your event handler:
async void Button_Click(object sender, RoutedEventArgs e)
{
if (_semaphore.Wait(0))
{
await Test(); // moving code into separate method
_semaphore.Release();
}
}

Asynchronous Displaying in Windows Form Application

I don't think the following question is rarely seen. But since I don't know how to search for the right answer, so I'm still stuck on it.
I have a label in the form and I want to show something before another job is invoked:
private void btnLoadEvent_Click(object sender, EventArgs e)
{
lbStatus.Text = "Loading... ";
load();
}
private void load()
{
Thread.Sleep(5000);
lbStatus.Text = "Done";
}
The label won't show anything before load() is complete.
Then I changed my program usnig async/await:
private async void btnLoadEvent_Click(object sender, EventArgs e)
{
lbStatus.Text = "Loading... ";
await load();
}
private async Task load()
{
Thread.Sleep(5000);
lbStatus.Text = "Done";
}
It doesn't change anything. Does anyone have any idea?
2014/4/3:
As a note, I think I've figured out how async/await works. And to avoid misleading any possible reader, I list my final solution as follows:
private async void btnLoadEvent_Click(object sender, EventArgs e)
{
lbStatus.Text = "Loading... ";
string content = await loadAsync();
}
private async Task<string> loadAsync()
{
using (WebClient webClient = new WebClient())
{
string json = await webClient.DownloadStringTaskAsync(
"http://api.openweathermap.org/data/2.5/weather?q=Taipei,tw");
lbStatus.Text = "Done";
return json;
}
}
In practice, to meet the Decoupling Principle, "lbStatus.Text = ... " could be better moved from loadAsync() to btnLoadEvent_Click() although it works fine.
And thanks everyone who helped.
You didn't really go async. Thread.Sleep is blocking and because your async function never yields it will still block the call site. Use await Task.Delay(... instead.
private void btnLoadEvent_Click(object sender, EventArgs e)
{
lbStatus.Text = "Loading... ";
load();
}
private async Task load()
{
await Task.Delay(5000);
lbStatus.Text = "Done";
}
Try using a BackgroundWorker . Set your label.Text to Loading before executing the BackgroundWorker's RunWorkerAsync method. Do your stuff (like your Thread.Sleep(5000)) in the Do_Work event and change the status of your label in the RunWorkerCompleted event. Visit this link to see an example.
You need to use BackgroundWorker. Something like that.
private void button1_Click(object sender, EventArgs e)
{
label1.Text = "Loading";
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
load();
}
private void load()
{
System.Threading.Thread.Sleep(1000);
if(InvokeRequired)
this.Invoke(new Action(()=>label1.Text = "Done"));
}

Categories