I tried the below code to execute command in Task.Run.
SshClient ssh;
public Form1()
{
InitializeComponent();
//BackGround Login is needed.
ConnectionInfo info = new ConnectionInfo(hostNameOrIpAddr, portNo, userName,
new AuthenticationMethod[] {
new PasswordAuthenticationMethod(userName, passWord)
ssh = new SshClient(info);
ssh.Connect();
cmd = ssh.CreateCommand(commandString);
}
private void button1_Click(object sender, EventArgs e)
{
Task.Run(()=>{
SshCommand cmd = ssh.CreateCommand(commandString);
cmd.Execute();
Console.WriteLine(cmd.Result.ToString());
;});
}
But it doesn't work well.
The reason is probably to Dispose the stream immediatly after starting the task.
One of the ways to use async/await is as following:
Note: The async keyword turns a method into an async method, which allows you to use the await keyword in its body.
private async void button1_Click(object sender, EventArgs e) {
var result = await Task.Run(() => RunSshCmd());
Console.WriteLine(result);
}
Let's say running ssh command will take 5 seconds to finish, just example.
private string RunSshCmd() {
Thread.Sleep(5000);
return "Done.";
}
Note: await can only be used inside an async method.
Related
How can I wait for an async task to complete without freezing the whole Application?
This function works but Cout() gets called while the File is still downloading.
private void Btn_test_Click(object sender, EventArgs e)
{
var task = Task.Run(async () => { await DownloadWebFile("https://speed.hetzner.de/100MB.bin", AppDomain.CurrentDomain.BaseDirectory + "//100MB.bin"); });
Cout(DownloadSuccessMsg);
}
when I do this the whole Application freezes:
private void Btn_test_Click(object sender, EventArgs e)
{
var task = Task.Run(async () => { await DownloadWebFile("https://speed.hetzner.de/100MB.bin", AppDomain.CurrentDomain.BaseDirectory + "//100MB.bin"); });
task.Wait();
Cout(DownloadSuccessMsg);
}
How can I wait correctly before running other code depending on the downloaded file?
private static async Task DownloadWebFile(string url, string fullPath)
{
using var client = new DownloadManager(url, fullPath);
client.ProgressChanged += (totalFileSize, totalBytesDownloaded, progressPercentage) =>
{
SetProgressBarValue((int)progressPercentage);
};
await client.StartDownload();
}
You can mark the method as async void. Returning void from an asynchronous method is usually not a great idea, but in the case of an event handler it's usually considered acceptable.
private async void Btn_test_Click(object sender, EventArgs e)
{
await DownloadWebFile("https://speed.hetzner.de/100MB.bin", AppDomain.CurrentDomain.BaseDirectory + "//100MB.bin");
Cout(DownloadSuccessMsg);
}
So I'm basically trying to delay the invocation of filter process by 1.5 seconds to allow user to type multiple keystrokes in case they want to. If a new keystroke is typed, previously waiting task is cancelled and a new one starts waiting:
System.Threading.CancellationTokenSource token = new System.Threading.CancellationTokenSource();
private async void MyTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
token.Cancel();
await System.Threading.Tasks.Task.Delay(1500, token.Token);
this.filterText = (sender as TextBox).Text;
(this.Resources["CVS"] as CollectionViewSource).View.Refresh();
//Earlier I had tried this variant too:
//System.Threading.Tasks.Task.Delay(500, token.Token).ContinueWith(_ =>
//{
// this.filterText = (sender as TextBox).Text;
// (this.Resources["CVS"] as CollectionViewSource).View.Refresh();
//});
}
But the filter process (View.Refresh() line) hits immediately on first keystroke without waiting. My impression was that calling Cancel on the token would kill Delay() and thereby the continuation task too, before planting the next one, but apparently this scheme doesn't work.
What am I missing?
The proper way to handle this is not with Task.Delay and exceptions (as exceptions are for exceptional circumstances), but using a Timer with the Timer.Elapsed event.
E.g.
using Timer = System.Windows.Forms.Timer;
private readonly Timer timer = new Timer();
private static string newText = "";
public Form1()
{
timer.Interval = 1500;
timer.Tick += OnTimedEvent;
}
private void MyTextBox_TextChanged(object sender, EventArgs e)
{
timer.Stop(); // sets the time back to 0
newText = (sender as TextBox).Text; // sets new text
timer.Start(); // restarts the timer
}
private void OnTimedEvent(Object source, EventArgs e)
{
filterText = newText;
(Resources["CVS"] as CollectionViewSource).View.Refresh();
}
(Not sure this is 100% correct, but you get the gist.)
Old snippet relating to the discussions in the comments.
As the post says: this is not needed, as Task.Delay will link a listener to the CancellationToken, thus .Cancel() will block until all listeners have heard it.
using System.Threading;
using System.Threading.Tasks;
private CancellationTokenSource cts = new CancellationTokenSource();
private Task delayTask;
private async void TenantsFilter_TextChanged(object sender, TextChangedEventArgs e)
{
cts.Cancel();
if (delayTask != null) {
try{await delayTask;}
catch(TaskCanceledException){}
}
cts = new CancellationTokenSource();
try
{
delayTask = Task.Delay(1500, cts.Token);
await delayTask;
this.filterText = (sender as TextBox).Text;
(this.Resources["CVS"] as CollectionViewSource).View.Refresh();
}
catch(TaskCanceledException)
{
}
}
If this helps anyone, the following is correctly working for me. My mistake was that I incorrectly assumed that CancellationTokenSource is a signaling device and could be used multiple times. That is apparently not the case:
private System.Threading.CancellationTokenSource cts = new System.Threading.CancellationTokenSource();
private async void TenantsFilter_TextChanged(object sender, TextChangedEventArgs e)
{
cts.Cancel();
cts = new System.Threading.CancellationTokenSource();
try
{
await System.Threading.Tasks.Task.Delay(1500, cts.Token);
this.filterText = (sender as TextBox).Text;
(this.Resources["CVS"] as CollectionViewSource).View.Refresh();
}
catch(System.Threading.Tasks.TaskCanceledException ee)
{
}
}
Posting it here for my own record and just to let others check I'm still not doing anything wrong.
I have a private async void Button_Click method in my WPF which runs a very complicated SQL query which can run for several minutes.
I wish the user can stop this method by clicking another button.
My code is like this:
public partial class MainWindow : Window
{
private async void Button_Click(object sender, RoutedEventArgs e)
{
string SQL_Query= " a very long and complicated SQL query ... "
SqlCommand SQL_Query_cmd = new SqlCommand(SQL_Query, conn);
DataTable dt = new DataTable();
await Task.Run(() => {
using (SqlDataAdapter a = new SqlDataAdapter(SQL_Query_cmd))
{ a.Fill(dt);}
});
}
}
I read about BackgroundWorker in this link How to use WPF Background Worker.
But didn't understand how to integrate it into my code. I think, my "filling datatable" code is already asynchronous but I don't know how to stop it. Assume that the button which is going to end this method is called stop_btn and its Click method is called cancelButton_Click.
Please please please write your answer in a post, rather than comments. I will be greatly thankful.
Here is how you could use the IDbCommand.Cancel method and a CancellationTokenSource, to perform cancellation both on the server side and on the client side.
private IDbCommand _activeSqlCommand;
private CancellationTokenSource _cts;
private async void btnExecute_Click(object sender, RoutedEventArgs e)
{
// The _activeSqlCommand and _cts should be null here.
// Otherwise, you may end up with multiple concurrent executions.
Debug.Assert(_activeSqlCommand == null);
Debug.Assert(_cts == null);
var sqlQuery = "A very long and complicated SQL query...";
var localSqlCommand = new SqlCommand(sqlQuery, _connection);
var localCts = new CancellationTokenSource();
_activeSqlCommand = localSqlCommand;
_cts = localCts;
btnExecute.IsEnabled = false;
btnCancel.IsEnabled = true;
try
{
DataTable dataTable = await AsCancelable(Task.Run(() =>
{
var dt = new DataTable();
using (SqlDataAdapter a = new SqlDataAdapter(localSqlCommand))
a.Fill(dt);
return dt;
}, localCts.Token), localCts.Token);
// Here use the dataTable to update the UI
}
catch (OperationCanceledException) { } // Ignore
catch (SqlException ex) when (ex.ErrorCode == CANCEL_ERROR_CODE) { } // Ignore
finally
{
btnCancel.IsEnabled = false;
btnExecute.IsEnabled = true;
// The _activeSqlCommand and _cts should still have the local values here.
Debug.Assert(_activeSqlCommand == localSqlCommand);
Debug.Assert(_cts == localCts);
_activeSqlCommand = null;
_cts = null;
localCts.Dispose();
}
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
_activeSqlCommand?.Cancel();
_cts?.Cancel();
}
private static Task<T> AsCancelable<T>(Task<T> task,
CancellationToken cancellationToken)
{
var cancelable = new Task<T>(() => default, cancellationToken);
return Task.WhenAny(task, cancelable).Unwrap();
}
You'll have to figure out what kind of exception is thrown by the database server when the execution is canceled, and ignore this exception based on its ErrorCode or some other property.
Testing a bit TPL.
I use this code and it works:
async void button1_Click(object sender, EventArgs e)
{
MyClass2 mc2 = new MyClass2();
label1.Text = "Start";
List<string> list = await mc2.GetInfosAsync("test123");
label1.Text = "";
list.ForEach(x => label1.Text += x + "\n");
}
class MyClass2
{
public Task<List<string>> GetInfosAsync(string txt)
{
return Task.Factory.StartNew<List<string>>(() => GetInfos(txt));
}
public List<string> GetInfos(string txt)
{
//doing long-listbuilding-operation
}
}
But I'm wondering if this is best practice of using async and await keywords, I feel a bit uncomfortable by "manipulating" the signature of button1_click event.
Using async on windows form event handler is correct and recommended way to do. If you don't use async await, you may see deadlock (unless you are using ConfigureAwait(false)).
Use async await all the way in your code. Don't use Wait() or Result
One important thing, keep all logic in separate method to make unit testable. It will be difficult to test async void. You cannot change method to async Task
// Will result in compilation error
private async Task button1_Click(object sender, EventArgs e)
// Because of event handler signature
public delegate void EventHandler(object sender, EventArgs e);
One good example to handle this is mentioned in msdn article mentioned below
public async void button1_Click(object sender, EventArgs e)
{
await this.ButtonClickHandlerAsync()
}
// Unit test this
public async Task ButtonClickHandlerAsync()
{
MyClass2 mc2 = new MyClass2();
label1.Text = "Start";
List<string> list = await mc2.GetInfosAsync("test123");
label1.Text = "";
list.ForEach(x => label1.Text += x + "\n");
}
More details-
https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
PS: I am assuming your question is about "Is using async on winform button click event handler good practice"? Technically async is not part of method signature (only method name and parameters). In case your question is actually about signature then please ignore this answer.
I implemented this in a solution for login. You can do it like this.
private async void metroButton1_Click(object sender, EventArgs e)
{
string res= await login();
if (res.Equals("true"))
{
this.Hide();
MainMDIParent mdi = new MainMDIParent();
mdi.Show();
btnLogin.Enabled = true;
}
else
{
MessageBox.Show("Invalid User Credentials", "LOgin", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
txtPassword.Text = "";
txtUsername.Text = "";
btnLogin.Enabled = true;
}
}
There is another approach to achieve this.
Parallel.foreach("list",(currentelement) =>
{
enter code here
});
Basically this will work as async.
There are several scenarios where I need to invoke multiple asynchronous calls (from the same event handler) that can proceed independently of each other, with each one having its own continuation for updating the UI.
The following naive implementation causes the three asynchronous operations to be executed sequentially:
private async void button_Click(object sender, RoutedEventArgs e)
{
nameTextBox.Text = await GetNameAsync();
cityTextBox.Text = await GetCityAsync();
rankTextBox.Text = await GetRankAsync();
}
There's an MSDN example that suggests separating the creation of the tasks from their respective await statements, allowing them to be run in parallel:
private async void button_Click(object sender, RoutedEventArgs e)
{
var nameTask = GetNameAsync();
var cityTask = GetCityAsync();
var rankTask = GetRankAsync();
nameTextBox.Text = await nameTask;
cityTextBox.Text = await cityTask;
rankTextBox.Text = await rankTask;
}
However, the limitation of this approach is that the task continuations are still registered sequentially, meaning that the nth continuation can't execute before all its preceding n−1 continuations have completed, even though its task may be the first to complete.
What is the best pattern for getting the asynchronous tasks to run in parallel, but have each continuation run as soon as its respective task completes?
Edit: Most of the answers suggest awaiting on Task.WhenAll, like below:
private async void button_Click(object sender, RoutedEventArgs e)
{
var nameTask = GetNameAsync();
var cityTask = GetCityAsync();
var rankTask = GetRankAsync();
await Task.WhenAll(nameTask, cityTask, rankTask);
nameTextBox.Text = nameTask.Result;
cityTextBox.Text = cityTask.Result;
rankTextBox.Text = rankTask.Result;
}
However, this does not meet my requirement, as I need each continuation to execute as soon as its respective task completes. For example, suppose that GetNameAsync takes 5 s, GetCityAsync takes 2 s, and GetRankAsync takes 8 s. The implementation above would cause all three textboxes to only be updated after 8 s, even though the results for nameTextBox and cityTextBox were known much earlier.
The traditional approach was to use ContinueWith for registering the respective continuation to each asynchronous task:
private async void button_Click(object sender, RoutedEventArgs e)
{
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
await Task.WhenAll(
GetNameAsync().ContinueWith(nameTask => { nameTextBox.Text = nameTask.Result; }, uiScheduler),
GetCityAsync().ContinueWith(cityTask => { cityTextBox.Text = cityTask.Result; }, uiScheduler),
GetRankAsync().ContinueWith(rankTask => { rankTextBox.Text = rankTask.Result; }, uiScheduler));
}
With C# 5, it is now preferable to use an await-style pattern. This may be most easily achieved by splitting up each task–continuation pair into its own method:
private async void button_Click(object sender, RoutedEventArgs e)
{
await Task.WhenAll(
PopulateNameAsync(),
PopulateCityAsync(),
PopulateRankAsync());
}
private async Task PopulateNameAsync()
{
nameTextBox.Text = await GetNameAsync();
}
private async Task PopulateCityAsync()
{
cityTextBox.Text = await GetCityAsync();
}
private async Task PopulateRankAsync()
{
rankTextBox.Text = await GetRankAsync();
}
Defining all these trivial methods quickly become cumbersome, so one may condense them into async lambdas instead:
private async void button_Click(object sender, RoutedEventArgs e)
{
await Task.WhenAll(
new Func<Task>(async () => { nameTextBox.Text = await GetNameAsync(); })(),
new Func<Task>(async () => { cityTextBox.Text = await GetCityAsync(); })(),
new Func<Task>(async () => { rankTextBox.Text = await GetRankAsync(); })());
}
If this pattern is used frequently, it would also be helpful to define a utility method that can take the Func<Task> lambdas and execute them, making our event handler's code more concise and readable:
public static Task WhenAllTasks(params Func<Task>[] taskProducers)
{
return Task.WhenAll(taskProducers.Select(taskProducer => taskProducer()));
}
private async void button_Click(object sender, RoutedEventArgs e)
{
await WhenAllTasks(
async () => nameTextBox.Text = await GetNameAsync(),
async () => cityTextBox.Text = await GetCityAsync(),
async () => rankTextBox.Text = await GetRankAsync());
}
A simpler alternative would be:
private async void button_Click(object sender, RoutedEventArgs e)
{
var results = await Task.WhenAll(
GetNameAsync(),
GetCityAsync(),
GetRankAsync()
);
nameTextBox.Text = results[0];
nameCityBox.Text = results[1];
nameRankBox.Text = results[2];
}
No closures, no extra state machines.
As I understand it, you need to query three async resources and only update the UI once all three have returned. If that's correct the Task.WhenAll control is idea to use. Something like
private async void button_Click(object sender, RoutedEventArgs e)
{
string nametext = null;
string citytext = null;
string ranktext = null;
await Task.WhenAll(
async () => nametext = await GetNameAsync(),
async () => citytext = await GetCityAsync(),
async () => ranktext = await GetRankAsync()
);
nameTextBox.Text = nametext;
nameCityBox.Text = citytext;
nameRankBox.Text = ranktext;
}
private async void button_Click(object sender, RoutedEventArgs)
{
var nameTask = GetNameAsync();
var cityTask= GetCityAsync();
var rankTask= GetRankAsync();
System.Threading.Tasks.Task.WaitAll(nameTask, cityTask, rankTask);
nameTextBox.Text = nameTask.Result;
cityTextBox.Text = cityTask.Result;
rankTextBox.Text = rankTask.Result;
}
More details: https://msdn.microsoft.com/pt-br/library/dd270695(v=vs.110).aspx