Dispatcher Invoke(...) VS Begininvoke(...) Confusion

Dispatcher Invoke(...) vs BeginInvoke(...) confusion

When you use Dispatcher.BeginInvoke it means that it schedules the given action for execution in the UI thread at a later point in time, and then returns control to allow the current thread to continue executing. Invoke blocks the caller until the scheduled action finishes.

When you use BeginInvoke your loop is going to run super fast since BeginInvoke returns right away. This means that you're adding lot and lots of actions to the message queue. You're adding them much faster than they can actually be processed. This means that there's a long time between when you schedule a message and when it actually gets a chance to be run.

The actual action that you're running uses the field _number. But _number is being modified by the other thread very quickly and while the action is in the queue. This means that it won't display the value of _number at the time you scheduled the action, but rather what it is after it has been continuing on in it's very tight loop.

If you use Dispatcher.Invoke instead then it prevents the loop from "getting ahead of itself" and having multiple scheduled events, which ensures that the value that it's writing is always the "current" value. Additionally, by forcing each iteration of the loop to wait for the message to be run it makes the loop a lot less "tight", so it can't run as quickly in general.

If you want to use BeginInvoke the first thing you really need to do is slow down your loop. If you want it to update the text every second, or ever 10ms, or whatever, then you can use Thread.Sleep to wait the appropriate amount of time.

Next, you need to take a copy of _number before passing it to the Dispatcher so that it displays the value at the time you scheduled it, not at the time it is executed:

while (true)
{
if (_number++ > 10000)
_number = 0;
int copy = _number;
this.Dispatcher.BeginInvoke(new Action(() => UpdateText(copy))
, System.Windows.Threading.DispatcherPriority.Background, null);
Thread.Sleep(200);
}

private void UpdateText(int number)
{
this.Text = number.ToString();
}

Control.Dispatcher.BeginInvoke() and Control.Dispatcher.Invoke() order execution is confusing?

BeginInvoke calls the Action you pass to it asynchronously on the thread that is associated with the Dispatcher while Invoke calls that action synchronously.

In other words, Invoke immediately executes what ever Action you pass to it while BeginInvoke puts the action you pass to it on the Dispatcher queue which is like a list of the things the Dispatcher is going to do but with no guarantee when that is going to happen or as soon as the dispatcher has finished doing the other things waiting on that queue.

So sometimes the Dispatcher might be busy doing something else and puts the action you pass to BeginInvoke on the queue's end until it can execute it, and then it executes whatever action you pass to Invoke immediately and that is the reason for the order differences.

Confused by the behavior of Dispatcher.BeginInvoke()

So if I understand your question correctly, you're saying that this code works exactly the way you want, but you're just trying to understand how (and why) it works?

Here's how it works. First, your thread runs this code:

Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window = new Window();
window.ShowDialog();
}));

That queues your action on the main (UI) thread's dispatcher queue, and then returns immediately: your worker thread continues running.

When the Application first started up (typically via the compiler-generated code that initializes your App.xaml object, though you can also do it explicitly by calling Application.Run), it started its message loop, which goes something like this (pseudocode, very very simplified):

public class Application {
public void Run() {
while (!Exited && action = Dispatcher.DequeueAction())
action();
}
}

So at some point shortly after you queue the action, the UI thread will get around to pulling your action off the queue and running it, at which point your action creates a window and shows it modally.

The modal window now starts its own message loop, which goes something like this (again, very simplified):

public class Window {
public bool? ShowDialog() {
DisableOtherWindowsAndShow();
while (!IsClosed && action = Dispatcher.DequeueAction())
action();
EnableOtherWindowsAndHide();
return DialogResult;
}
}

Later, your worker thread runs this code:

Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window.Close();
}));

Again, your action is queued to the UI thread's dispatcher queue, and then the BeginInvoke call returns immediately and your worker thread continues running.

So sooner or later, the UI thread's message loop will get around to dequeuing and executing your action, which tells the window to close. This has essentially the same effect as the user clicking the title bar's "X" button, which of course is perfectly OK to do even when you're inside a modal dialog. This causes ShowDialog's message loop to terminate (because the window is now closed), at which point the dialog is hidden and the other windows are re-enabled, ShowDialog returns, your original (ShowDialog) action is complete and so returns, and control falls back to the original message loop in Application.Run.

Note that there's one dispatcher queue per thread, not one per message loop. So your "close" action goes into the same queue that your "show dialog" action did. It's a different piece of code doing the message-loop polling now (the one inside ShowDialog instead of the one inside Application.Run), but the basics of the loop are the same.

Application.Current.Dispatcher.BeginInvoke(action) VS. Application.Current.Dispatcher.Invoke(action) (WPF)

For your purpose, there is no difference between Invoke and BeginInvoke. Dispatcher is a task scheduler associated with one specific thread. You can add tasks via Invoke or BeginInvoke to a prioritized queue of the Dispatcher, the Dispatcher will execute them one by one on the thread it associated with. But Invoke will block caller thread until task was completed, so using it may has negative effect on your working thread.

Invoke and BeginInvoke

With Invoke the method gets executed and the application waits for it to complete.

With BeginInvoke the method is invoked Asychnronously and the application continues to execute while the method referenced in BeginInvoke is executed.

With BeginInvoke you need to call EndInvoke to get the results of the method you executed using BeginIvnoke.

You should not update GUI components in BeginXXX methods as they are run in another thread to the GUI thread, contrary to your Invoke method. You cannot access GUI components in a different thread to the GUI thread.

Hope this helps!



Related Topics



Leave a reply



Submit