Can someone help me on following problem ?
I want to show a "Progress Bar" that is "Indeterminate = TRUE" while the user is connecting to SSH server. If the the connection to the server is successfull, then the MainWindow with progressbar should be closed and a new Window will be opened. The progressbar is placed on a other Window named "LoginState".
Here a little codexample how I tried it:
Code from Login Methode:
private async void Login(object sender, RoutedEventArgs e)
{
loginstate.Show();
dispatcherlogin = Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DelegateLogin(ProcessLogin));
await dispatcherlogin.Task;
if(ProofIfUserActive() == true)
{
loginstate.Close();
mainoverview.Show();
Close();
}
private void ProcessLogin()
{
// SSH and MySQL Connection
}
My problem:
If the Button is pressed the Methode "Login" will be triggered. In this moment the progress bar appeares and the connection to the ssh server start. The problem is, that I can't see any progress in the progress bar while it's opened, and after the succesfull connection, the main window with the progressbar will be closed and the other window will be opened.
I tried it also with the Dsipatcher.Invoke Method, but without success. Is that even possible what I want, because how I unterstood it, the wpf application is runnung in UI "STA Thread". Multithread is not possible, because I got immedtiatly a Exception that only STA threads are allowed.
Thanks developers for the help ;)
CodePudding user response:
Dispatcher.BeginInvoke
will ask the IU thread to do the login. So while the connection is being established the UI thread is blocked and cannot update any window or do anything else UI related.
To solve this the typical solution is to move the time consuming operation to a background thread. This can be done by using Task.Run
. This would free the UI thread to update the UI and respond to user input.
A typical problem with running things on a background thread is trying to update the UI. This is not allowed, you will need a clean separation between any code that will be running in the background and UI code.
It is possible that some components (usually COM components) have more complicated rules regarding threading, but I would not expect MySQL or SSH to have such requirements.
CodePudding user response:
You should not put the blocking code on the Dispatcher
. Dispatcher
is keeping the UI thread alive by implementing a message queue. If you let the Dispatcher
execute your long running operation, you are blocking the message queue that holds jobs that execute UI related operations like input events and rendering - the UI freezes.
Instead execute the long running CPU bound operations on a background thread which you can await.
Please note: the best solution is always to use an existing async API of your server (or the library used to interact with your server).
For example the HttpClient
exposes a naturally async API.
IO operations like connecting to a database are not CPU bound and should generally not be executed on a background thread using Task.Run
!
private async void Login(object sender, RoutedEventArgs e)
{
loginstate.Show();
await Task.Run(ProcessLogin);
loginstate.Close();
...
}
The cleaner solution is, in case your login service is event driven, to use TaskCompletionSource
to implement asynchronous behavior.