C#, WPF, Automatically call Dispatcher.Invoke when needed? - c#

I have a program with a Geospace map embedded into it. The event handling for the map is handled on a separate thread to keep the map responsive (for example, the events that fire when the map is clicked).
The problem I am having is when the map fires an event, my program needs to update some things in it's gui, and also call back into the map to handle placing pictures on the map.
I tried wrapping the entire event handler method in this.Dispatcher.Invoke, which puts me back on the main UI thread. This works great for updating my GUI, but when i call back into the map, I'm still on the UI thread which can cause some problems in the map.
Basically, in order to make this work, I'm going to have to run dispatcher.invoke each time I want to change a control on my gui. Is there a way I can automatically do this without wrapping each call in dispatcher.invoke? I hope this all makes sense.
Heres some example code for the event I'm talking about..
private void Map_OnMapClicked(object sender, MapClickedEventArgs e)
{
this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() =>
{
// Do something to update my gui
}));
Map.DoSomethingInTheMap();
this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() =>
{
// Do something to update my gui
}));
//etc etc etc
}

If you need to keep each respective operation in its own synchronization context, this is unfortunately the best approach. You'll need to Invoke using the Dispatcher whenever you update your GUI.
Here are a couple of suggestions for making this easier:
Try to batch your GUI operations. In addition to requiring less code (via less invoke calls), you'll get better performance. Each Dispatcher.Invoke call carries a fair amount of overhead, since it posts a message into the Dispatcher's message queue which must be processed.
Consider using Dispatcher.BeginInvoke to avoid blocking, unless you really need to wait.
If you can use the Task Parallel Library from .NET 4 (or the backport to 3.5sp1 in the Rx Framework), you might want to consider reworking this to use Task instances synchronized to the GUI thread. By creating a TaskScheduler using FromCurrentSynchronizationContext, you can schedule tasks to run on the GUI easier than the Dispatcher Invoke calls. This also can give you some control over batching, since you can schedule them, and block/wait as needed, very easily.

You could use something like PostSharp or try to condense your UI updates to single method calls where you invoke once and do a lot. Or even a pattern like this (it's Winforms but the idea is the same):
private void UpdateToolStripItemText(ToolStripItem toolStripItem, string text)
{
if (InvokeRequired)
{
Invoke(new UpdateToolStripItemTextDelegate(UpdateToolStripItemText), new object[] { toolStripItem, text });
}
else
{
if (text != null)
{
toolStripItem.Text = text;
}
}
}

Related

How to Invoke multiple controls in C#

I have a C# program seems stuck at random time, and after a random while it recovered itself! When it stuck, I can see the memory growth, and when it recover, the memory usage just drops to normal. The CPU usage seems normal all the way and there is no files is written or read (as designed).
The program calls an external (3rd party) DLL function to communicate with hardware, and updates the UI from the DLL's callback which running on a different thread. I have checked the code and found nothing suspicious apart from the following code (redacted):
private void Func(StructType para) {
if (labelA.InvokeRequired) {
labelA.BeginInvoke(new MethodInvoker(() => Func(para)));
return;
}
if (labelB.InvokeRequired) {
labelB.BeginInvoke(new MethodInvoker(() => Func(para)));
return;
}
labelA.Text = para.A;
labelB.Text = para.B;
}
I wonder if this is a proper way of update the UI element from another thread? If not, how to revise it?
In fact, I invoke 6 labels and another form (optionally). It seems working fine for most time but occasionally stuck. I can't post all code here for obvious reason, but just trying to troubleshot from where I doubt most.
Thanks in advance for any suggestions!
You don't need to individually check each each control to determine if you need to invoke it - there is only one UI thread, thus, that check is only useful once. Keep in mind - modifying any UI component is almost certain to cascade into a whole bunch of other reads/writes to other UI components; as a result of that, you have to make the assumption that if you are touching any UI object, you have to assume you're touching all UI components.
With that in mind, I'd recommend you perform your invoke check once, and I recommend performing the check and invoke on the parent control of both labels.
Assuming this refers to the class that is the parent to both those labels, I would modify your code as follows:
private void Func(StructType para) {
if (this.InvokeRequired) {
// Elide the explicit delegate declaration; it's not necessary.
this.BeginInvoke( Func(para) );
// Elide the return statement - multiple returns are messy, and in this case, easily removed.
}
else {
labelA.Text = para.A;
labelB.Text = para.B;
}
}
Be aware that InvokeRequired returns false if the object is disposed, even if the calling thread is not the UI thread.

Update the GUI from another thread in C# - change back to the main thread or not?

I know that simplest way to update a label from another thread is:
void DoSomething()
{
if (InvokeRequired)
{
Invoke(new MethodInvoker(DoSomething));
} else
{
// Do Something
}
}
My question is if instead of the if that require to update the GUI from another thread is it possible to change back to the main thread and update the GUI from there ?
Actually, the simplest way to do this is
Invoke(new MethodInvoker(DoSomething));
if you call it from another thread for sure, ie. if you know, that InvokeRequired will always be true.
Also, you could use a WinForms Timer to poll for changes of, say, a text field. This timer runs in the GUI thread. That is a pretty good solution if you have hundreds of events per second. Or at least "a lot of". This way you don't have too many switches to the GUI thread (which always take considerable amount of time).
Of course its possible ... you can use class called Dispatcher (System.Windows.Threading). The main purpose of this class is to dispatch "requests/calls" on thread ... and for gui thread there is instance of such dispatcher available for all controls. You can find this instance as member of your Window for example ...
The catch is that you using dispatcher alraedy (in code you posted) in some way ... if you call Invoke inside Form this default/gui dispatcher is used. And "IF" is there for reducing count of invocation from gui thread itself.
It works like "am i in ui thread? No? Then give dispatcher request of calling this same method on UI thread! ... Am i in UI Thred? Yes! Ok, i am doing something."
If you are 100% sure that you call this form other than UI thread, you can throw away that IF and just call dispatcher directly.
MyForm.Dispatcher.Invoke( mydelegate, params[] )
Or using some lambda instead of delegate or MethodInvoker ...
MyForm.Dispatcher.BeginInvoke( (Action)(()=>{ textbox.text = result; }), null);
And at all ... you can store (in form.load event for example) reference to UI Dispatcher to use in different class (some working class doing stuff on other )
If you creating some bigger UI stuff, my suggest for better UI and easier handling stuff like this is: ... consider some study of WPF and MVVM pattern and property change notifications.... it will give you very strong tool with "self updated" and very scalable UI and layers between datas, working threads and UI.

Clarification on updating GUI from a separate Thread using an anonymous method

I've found what looks like a very simple solution to my current situation.
My current situation is that I want to do some I/O-heavy operations on a new Thread, so that I do not bog down my GUI Thread. I have a function written, as a member of my Form, that does these I/O operations already, but running it on the GUI Thread really makes the application a pain to use. So my plan was to just run this function in a new Thread. So, I created a Thread variable, in my form, and am trying to get it to use that function as the ThreadStart parameter. It does not seem to like it, though.
I found an elegant looking solution, as a response to another thread, here.
///...blah blah updating files
string newText = "abc"; // running on worker thread
this.Invoke((MethodInvoker)delegate {
someLabel.Text = newText; // runs on UI thread
});
///...blah blah more updating files
From the looks of that response, I could run this function in a new Thread and then use an anonymous function to update my Form when the Thread has finished its calculations. I'm just not good enough to fill in the blanks from that response, though.
Everything I seem to read about Threads says that my ThreadStart function needs to be a static method in a new class. That response seems to suggest that I can do it within my Form class though, so that the this reference still references my Form instance. Otherwise, if my ThreadStart parameter were a different class, I'd have to pass in references to the Form instance, and that seems like more code, right?
Would anybody mind helping me fill in the context for that response? Thanks in advance!
There are a lot of ways you can do this. A very simple, straightforward one that's been around for a number of versions is to use the BackgroundWorker. It is designed for exactly this case. It has a DoWork method that runs in a background thread, and a Completed event that is fired after the work is done which runs in the UI thread (so you don't need to call invoke or anything to update the UI with the results). It even has support built in for reporting progress (the report progress event also runs in the UI thread) so you can easily update a progress bar or status text.
MSDN has some examples as well, and you can find lots more through some simple searches.
Another option, made available through C# 4.0, is to use Tasks. You can start a new task which will be run in a background thread, and then you can add a continuation which will be in the UI thread.
Here is a simple example:
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew(() => doStuffInBackground())
.ContinueWith(task => updateUI(), TaskScheduler.FromCurrentSynchronizationContext());
}
private void updateUI()
{
throw new NotImplementedException();
}
private void doStuffInBackground()
{
throw new NotImplementedException();
}
You can of course do whatever you want in the actual lambdas that I have there, or you could even remove the lambdas and put methods in there directly as long as you ensure the signatures are correct. You could also continue chaining these continuations if you wanted, allowing you to, for example, to task 1, update a label, then do task 2, update a label, etc. The main disadvantage is that it's not good at updating a progress bar frequently inside of a loop, the way a BackgroundWorker can.

C# multithreading - updating the GUI with background events

I'm a newbie to C# and multithreading so I apologise if this is a duplicate question but being a novice it appears my question is slightly different to others I have read.
My GUI runs in one (main) thread. It calls a background task (in a dll -- that I am writing too) that runs in a separate thread. The dll has NO knowledge of the GUI (i.e. it cannot reference the GUI class).
Now, say I want to update a progress bar on the GUI based on the status of the dll thread -> What I'm doing is creating an event in the dll that every X per cent will fire and the GUI will subscribe to this event. When the event is fired, the GUI will update the progress bar.
My questions:
Is the method of creating events the best way (bearing in mind the dll cannot reference the GUI)?
How do I ensure my above method is 'event safe'? Should I pass the progress percentage in the event to be thread safe or is there more to it?
Do I need to use Invoke when updating the GUI? I saw a post that suggested I did but I don't understand why since the updating of the bar is being done in the GUI thread??!
Hope you can clarify this for me!
Thanks
1.-I use that method all the time and yes it will work
2.-Just pass a int to the event handler and the variable will be safe to read. however when you are fireing the event from code do it like this
private void UpdatePercentage(int a)
{
var myEvent = PercentageUpdatedEvent
if(myEvent != null)
myEvent(this, new ProgressBarEventArgs(a));
}
The reason for this is so if the event is unsubcribed between the null check and the calling you won't get a exception.
3.-As everyone else has mentioned you will need to call Invoke as the event will be running on the dll's thread. However with controls it is legal to call a BeginInvoke without a EndEnvoike so the call will be non blocking on the dll's thread.
Here is the pattern I always use
private myClass_OnPercentageUpdatedEvent(object a, ProgressBarEventArgs e)
{
if(progressBar.InvokeRequired)
progressBar.BeginInvoke((Action<object,ProgressBarEventArgs>)myCless_OnPercentageUpdatedEvent, a, e);
else
{
progressBar.Value = e.Value;
}
}
Look into the BackgroundWorker class. It sounds like it fits your scenario pretty well.
This link on MSDN explains how to use it: http://msdn.microsoft.com/en-us/library/cc221403%28VS.95%29.aspx
Keep in mind that under most circumstances, the events raised from your background task will also run on the background thread. No thread context switch happens automatically at all.
To understand why, you have to consider what an event is; just a certain type of Delegate object. You are setting a Delegate to that event from the main thread... but that delegate will actually be called within the background thread, in the code that triggers the event.
So yes; you would need to make sure you are moving things over to run on the GUI thread from within that event handler.
To answer (3) you will need to use Invoke. The event-handlers are going to be run from the background thread, not the GUI thread.
If you spin off a thread, you need to create a delegate, that can safely invoke your main thread with the appropriate parameters.
delegate void UpdateDelegate(int val)
void Update(int val)
{
if(this.InvokeRequired())
{
Invoke(new UpdateDeleage(Update),new object[] {val});
return;
}
this.MyProgressBar.Value = val;
}
Call Update from your separate thread as you would if calling it from your main thread. Once the thread determines that your main thread needs invoked to pass the value, it will invoke it with your delegate, with the parameters you passed. Otherwise, it will simply skip the block and set your values.
e.g.
...
new Thread(()=>IncrementValues()).Start();
...
void IncrementValues()
{
while(true)
Update(new Random(0,10));
}
I have on my blog a few different approaches to this problem, with the advantages/disadvantages of each. In summary, I recommend using the Task class.

Using VerifyAccess and CheckAccess methods of DispatcherObject

While going through this article I came across this statement -
If you are writing your own WPF
objects, such as controls, all methods
you use should call VerifyAccess
before they perform any work. This
guarantees that your objects are only
used on the UI thread, like this
//Using VerifyAccess and CheckAccess
public class MyWpfObject : DispatcherObject
{
public void DoSomething()
{
VerifyAccess();
// Do some work
}
public void DoSomethingElse()
{
if (CheckAccess())
{
// Something, only if called
// on the right thread
}
}
}
I haven't seen this in any of the custom controls I have come across(as far as I remember).
Do you use this while building custom controls?
Is it must to do this or just nice to have?
Anyone ever faced any issue due to absence of this in your controls?
Nah, never used this. And never noticed somebody use it in the context of Custom Controls. This rule is not followed in WPF Toolkit too.
This approach not only pollutes the code but also makes your custom control responsible for something it shouldn't care about. Consider situation where you always doing:
// Don't do this in all methods of your custom control!
public void Foo()
{
if (!CheckAccess())
{
Dispatcher.Invoke(()=> Foo()); // Transit to UI Thread
return;
}
// .. do work in UI.
}
At first glance this code looks fine. If you are not in UI thread, transit to UI thread, perform operation and return result. Right? - WRONG!
Problem 1. When you call Dispatcher.Invoke() you block calling thread until your request is processed by UI thread. This leads to poor performance. Of course, you can change this to Dispatcher.BeginInvoke() now your clients should be aware that their operation is done asynchronously. I.e. if client writes something to control, and then immediately reads it back there is no guarantee, that the operation already executed by UI thread.
Problem 2. Consider subsequent calls to the method Foo() from non UI thread. For example it's called in cycle:
// Somewhere not in UI
for (int i = 0; i < 1000000; i++)
{
control.Foo(); // Looks good, but performance is awful!
}
Instead of blocking calling thread 1000000 times, developer could implement one check in the calling thread and transit to UI when necessary, instead of unconsciously jumping back and worth between threads.
Furthermore WPF will make this check for you when you access UI element from non-UI thread. It screams loud enough to crush application and be heard by developer who has done something wrong :).
Hope this helps.

Categories