WPF Dispatcher Thread Freeze main window - c#

Instead of working in the background - this code still freeze my program:
private void button_Click(object sender, RoutedEventArgs e)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Thread.Sleep(5000);
label.Content = "Done";
}), DispatcherPriority.Normal);
}
I have tried with Thread/Tasks, thread example:
private void button_Click(object sender, RoutedEventArgs e)
{
var t = new Thread(new ThreadStart(runtask));
t.Start();
}
private void runtask()
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Thread.Sleep(5000);
label.Content = "Done";
}), DispatcherPriority.Normal);
}
Task example:
private void button_Click(object sender, RoutedEventArgs e)
{
Task.Run(() =>
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
{
Thread.Sleep(5000);
label.Content = "Done";
}));
});
}
And still my program is freezing. Any suggestions?

From the documentation of the Dispatcher class:
Provides services for managing the queue of work items for a thread.
From the documentation of Dispatcher.BeginInvoke:
Executes the specified delegate asynchronously with the specified arguments on the thread that the Dispatcher was created on.
Here "asynchronously" refers to the secondary thread, not the main one. Because the main one is owned by the main Dispatcher. That means that every call of Invoke or BeginInvoke on that Dispatcher, from whatever Thread, will put the invoked Action in the queue of operations that the main Thread must execute, but from the point of view of the main Thread they will be executed synchronously, one after the other.
For example, if you put 3 Action like Thread.Sleep(1000); within 10 ms on the Dispatcher, whether with Invoke or BeginInvoke and from whether Thread, that Dispatcher will make the UI Thread to execute the 3 Action synchronously, so they will take a total of 3000 ms.
Maybe the documentation about BeginInvoke could have been written better, like:
Executes the specified delegate with the specified arguments on the thread that the Dispatcher was created on. The specified delegate is executed asynchronously from the point of view of the calling thread.
Now... Invoke or BeginInvoke?
Using Invoke, the secondary Thread is saying to the Dispatcher: let's execute this on the main Thread, and don't dare to return until your thread's job has finished. Then and only then I will continue.
For example, if you write this:
this.Dispatcher.Invoke(new Action(() =>
{
Thread.Sleep(5000);
Debug.WriteLine("After Sleep");
}));
Debug.WriteLine("Continuation on secondary Thread");
The Console will print after ~ 5000 ms:
"After Sleep"
"Continuation on secondary Thread"
Using BeginInvoke, instead, the Thread is saying: "hey, Dispatcher, queue this operation on the main Thread, but return as soon as possible so I can continue my job immediately".
In this case the Console will print immediately:
"Continuation on secondary Thread"
And after ~ 5000 ms:
"After Sleep"
Now, if your purpose is to execute some heavy operation on the background, you should learn about the async/await pattern, available from .NET 4.5 and C# 5.0.
In your example, I would write:
private async void button_Click(object sender, RoutedEventArgs e)
{
await Task.Delay(5000); // await a heavy operation executed in background
label.Content = "Done"; // control back to the UI Thread that executes this
}

You can use this small extension if your UI access is the last of your method.
https://mitsufu.wordpress.com/2015/08/03/dispatcher-switchto/
private void Button_Click(object sender, RoutedEventArgs e)
{
Task.Run(async () =>
{
//heavy background operation
await Dispatcher.SwitchTo();
Title = "ok";
});
}

Related

How to close WPF window inside of a Task

I need to run a task to check the connection.
My windows should not be frozen during this check.
So I start the Task, and close my window at the end of this task.
But this returns an exception: InvalidOperationException:'The calling thread cannot access this object because another thread owns it'.
Like this :
private void Window_ContentRendered(object sender, System.EventArgs e)
{
Task.Run(() =>
{
ConnectionState = false;
if (NetworkTools.CheckGlobalConnection() == (ConnectionStatus.NetworkConnectionSuccess, ConnectionStatus.ServerConnectionSuccess))
{
ConnectionState = true;
}
this.Close();
});
}
How do I close my window at the end of the task without freezing it and without having this exception ?
(I have a progress bar that rotates indefinitely)
Or you could just use async await. Task.Run will offload and the await will create a continuation on current SynchronizationContext. In turn giving control back to the UI and closing on the right thread.
private async void Window_ContentRendered(object sender, System.EventArgs e)
{
await Task.Run(() =>
{
ConnectionState = false;
if (NetworkTools.CheckGlobalConnection() == (ConnectionStatus.NetworkConnectionSuccess, ConnectionStatus.ServerConnectionSuccess))
ConnectionState = true;
});
this.Close();
}
Also as noted, Calling ConfigureAwait(false), would not be the right thing to do in this case
Use Dispatcher to queue window closing logic on the unique UI thread.
Something like
Dispatcher.Invoke(
() =>
{
// close window here
});
Whatever is passed into .Invoke(...) as a delegate, is invoked on the UI thread and hence has right to access all UI elements. It is common (and the only correct) way to deal with UI-mutations within non-UI threads.
As an alternate method you can use ContinueWith
private void Window_ContentRendered(object sender, System.EventArgs e)
{
Task.Run(() =>
{
// Your code
}).ContinueWith((tsk) =>
{
this.Close();
}, TaskScheduler.FromCurrentSynchronizationContext());
}

How to update label control of the parent UI window from child window in sequential manner in wpf?

I have tried to find out the answer but no real answer found. Can anyone answer following? I am trying to update status in the parent window by calling Dispatcher Method, but I see it does not update the status in sequential manner. I see the status update in the mainwindow as follow:
First process started...
First Process done!
Third Process done!
Instead of delay between the UpdateStatus, there can be some other method or task. So, Why it does not update other status? Any real answer please?
private void Button_Click(object sender, RoutedEventArgs e)
{
UpdateStatus("First Process started...");
Thread.Sleep(5000); //or any method
UpdateStatus("First Process done!");
Thread.Sleep(5000); //or any method
UpdateStatus("Second Process started...");
Thread.Sleep(5000); //or any method
UpdateStatus("Second Process done!");
Thread.Sleep(5000); //or any method
UpdateStatus("Third Process started...");
Thread.Sleep(5000); //or any method
UpdateStatus("Third Process done!");
}
private void UpdateStatus(string message)
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
{
MainWindow.main.lblTest.Content = message;
}
));
}
A single thread can't both update the UI and sleep at the same time.
You could wait asynchronously between the status updates though:
private async void Button_Click(object sender, RoutedEventArgs e)
{
UpdateStatus("First Process started...");
await Task.Delay(5000);
UpdateStatus("First Process done!");
await Task.Delay(5000);
UpdateStatus("Second Process started...");
await Task.Delay(5000);
UpdateStatus("Second Process done!");
await Task.Delay(5000);
UpdateStatus("Third Process started...");
await Task.Delay(5000);
UpdateStatus("Third Process done!");
}
private void UpdateStatus(string message)
{
MainWindow.main.lblTest.Content = message;
}
I hope this will make it more clear.
private async void Button_Click(object sender, RoutedEventArgs e)
{
// I run on the main thread and return immediately
await SearchForAliensAsync();
}
private async Task SearchForAliensAsync()
{
// I run on (capture) the caller thread (main thread)
UpdateStatus("Searching for aliens...");
/* Dispatch the dirty work on a background thread and return immediately,
* so that the caller thread (main thread) remains responsive.
* If you don't do that, the main thread will get blocked.
* From the user perspective the UI is frozen.
* The main thread will search infinitely for aliens,
* instead of doing its main job - poping and dispatching messages from
* its message queue (Win32 is event driven).
* The operating system will keep notifying the main thread,
* that the user has clicked on the window or smashed multiple keys on the keyboard,
* but the main thread won't listen, it's searching for aliens!
* The operating system monitors all main threads, by measuring what
* time has elapsed from the last call to GetMessage(...) and
* if the latter exceeds a certain amount, it will play a trick on you.
* The OS will create a transparent window and place it on top of the
* unresponsive one, so that it can detect the next angry mouse click
* and display the famous "Application is not responding" dialog...
*/
await Task.Run(() =>
{
// I run synchronously on the thread pool and I won't finish any time soon..
SearchForAliens();
});
// When my time comes, I'll be dispatched on the captured thread (main thread)
UpdateStatus("Aliens exist!");
}
You are running everything synchronously in UI thread, preventing any invoke until you finish (therefore no updates and then all updates at once). Simply move your code in task:
void Button_Click(object sender, RoutedEventArgs e) => Task.Run(() =>
{
... // rest of your code
});
and you should be fine (fine unless you press button twice, but that's easy to fix I guess).
Btw, you can also use another overload of invoke:
Dispatcher.Invoke(() => lblTest.Content = message);

Pause Thread While Another Thread Is Executing A Task

I created a Thread that executes a task, but i need to pause my Main thread until my secondary threads ends the task.
private void AquilesPL_Load(object sender, EventArgs e)
{
ThreadStart ts = new ThreadStart(RunTask)
Thread t = new Thread(ts);
t.Start();
SomeFunction1();
SomeFunction2();
//I need to pause the main thread here, if runtask() continue working
//if runt task ends, this main thread must to continue.
ReadFile();
CloseProgram();
}
private void RunTask()
{
//Some code that write a file
//RunTaskfunction ends, and i have to continue
}
private void ReadFile()
{
//Reading the file, this file has been written by RunTask
}
Thanks in advance.
but i need to pause my Main thread until my secondary threads ends the task.
This is typically a bad idea. A better solution is to disable the UI while the task is executing, then re-enable it when it's completed.
The TPL and async/await make this fairly straightforward. For example:
private async void AquilesPL_Load(object sender, EventArgs e)
{
var task = Task.Run(() => RunTask());
SomeFunction1();
SomeFunction2();
// Disable your UI controls
await task; // This will wait until the task completes,
// but do it asynchronously so it does not block the UI thread
// This won't read until the other task is done
ReadFile();
// Enable your UI controls here
}
If you can't use C# 5, you can do this via .NET 4 and the TPL:
private void AquilesPL_Load(object sender, EventArgs e)
{
var task = Task.Factory.StartNew(() => RunTask());
SomeFunction1();
SomeFunction2();
// Disable your UI controls
task.ContinueWith(t =>
{
// This won't read until the other task is done
ReadFile();
// Enable your UI controls here
}, TaskScheduler.FromCurrentSynchronizationContext());
}

How to wait a thread out of that thread without freeze my APP?

I'm running some scripts in runtime, but it's freezing my UI, I'm calling the CodeProvider inside a Thread, but it still freezing.
In my form I call:
var mre = new ManualResetEvent(false);
Thread tr = new Thread(() =>
{
Script sp = new Script();
code = textBox.Text;
sp.Comp(code);
mre.Set();
});
tr.Start();
mre.WaitOne();
I'm using the mre.WaitOne() because I want to wait the thread finish to keep running my code.
Tried to use the same way inside the Compile method too:
public bool Comps(string code)
{
var mre = new ManualResetEvent(false);
Thread tr = new Thread(() =>
{
//Code to generate a CompilerResult and generate the assembly
Run();
mre.Set();
});
tr.Start();
mre.WaitOne();
return true;
}
But while it's waiting it still freezing the UI.
Any ideas?
Thanks
I'm using the mre.WaitOne() because I want to wait the thread finish
to keep running my code.
What did you expect to happen if you force the calling thread to freeze until your processing thread has completed processing? Doing it this way, there is no point in having that extra thread and if the calling thread is the UI thread, of course it will freeze.
If you do background processing you cannot wait for the result synchronously, instead you have to notify the UI in some sort of fashion that the processing is done, i.e. using a callback or dispatching the result back to the UI in some other form.
The entire point of multi-threading is to allow the Thread to execute on it's own, independent of any other threads. What you want to do is use a callback to signal the completion of your thread and then have your UI respond to the completion.
The BackgroundWorker class has an event already built in for this purpose.
There are three events you want to subscribe to:
bw.DoWork +=
new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged +=
new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
DoWork is where your work will happen. ProgressChanged allows you to update the UI of progress. RunWorkerCompleted will pop the event with your DoWork function has completed.
This object handles the threading and can be set to run asynchronously by running the bw.RunWorkerAsync() call.
See the following page for detail for this:
http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx
As an example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(String.Format("UI thread: {0}", Thread.CurrentThread.ManagedThreadId));
this.Invoke(new MethodInvoker(delegate() { MessageBox.Show(String.Format("Invoke thread: {0}", Thread.CurrentThread.ManagedThreadId)); }));
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
MessageBox.Show(String.Format("Worker thread: {0}", Thread.CurrentThread.ManagedThreadId));
}
}
This example can be built by adding one button and one background worker to a form. Wire up the events through the events designer for the button1_Click and the backgroundWorker1_DoWork function. You should have three MessagesBoxes that pop up after clicking button1. You'll notice the Id for the UI thread and the Invoke thread are the same, which means that any processing you do from the invoke will cause your UI thread to wait. The third popup is from the worker thread, which has a different ID.
Use BeginInvoke when done. For example:
delegate void MyAction();
void Form1_Load( object sender, EventArgs e )
{
Thread tr = new Thread( () =>
{
Script sp = new Script();
code = textBox.Text;
sp.Comp(code);
BeginInvoke( new MyAction( ThreadOperationEnded ) );
} );
tr.Start();
}
void ThreadOperationEnded()
{
MessageBox.Show( "Finished!" );
}

Close a form from a thread

I have a Thread that starts in my main form
private void changePasswordbutton_Click_1(object sender, EventArgs e)
{
waitForm.Show();
Thread thread = new Thread(ProcessInkPresenter);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
waitForm.Hide();
waitForm.Dispose();
}
I want to close the waitForm inside the ProcessInkPresenter method (which is running on a thread) instead of waiting for the thread to complete.
How do I do this?
Thanks
Method signatures
private void ProcessInkPresenter()
Defined in the class header
Wait waitForm;
Your original code doesn't make sense. It shows a form, then starts a thread, then waits for that thread to complete. If you want the form to be run on it's own UI thread, have ProcessInkPresenter run on the same UI thread (which it should if it interacts with the UI) and have the form closed and be disposed of when ProcessInkPresenter completes, try this:
private void changePasswordbutton_Click_1(object sender, EventArgs e)
{
Thread thread = new Thread(state => {
using (var waitForm = new WaitForm()) {
waitForm.Activated += (s, e) => {
ProcessInkPresenter();
waitForm.Hide();
}
Application.Run(waitForm);
}
}
);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
If the worker thread does not have to interact with the GUI, then what you want is something like the following. Note that I make use of Invoke to make sure that the interaction with the UI is done on the UI thread. There is no need to check InvokeRequired here, since I already know for sure that I am on a background thread.
If you want to keep the same waitForm instance:
private void changePasswordbutton_Click_1(object sender, EventArgs e)
{
Thread thread = new Thread(state => {
try {
ProcessInkPresenter();
// If ProcessInkPresenter fails, this line will never execute
waitForm.Invoke(new Action(()=>waitForm.Hide()));
}
catch (Exception ex) {
// You probably want to do something with ex here,
// rather than just swallowing it.
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
waitForm.Show();
}
NOTE: It doesn't make sense to dispose your WaitForm if you have a single instance of it (your Wait instance). Either construct an instance each time you use it, or never dispose it and use .Hide() instead.

Categories