Should Control.InvokeRequired always be used when accessing UI controls - c#

We are building a .NET application using WinForms (3.5).
I have added a new feature recently, and started experiencing weird behavior when accessing certain controls. The problem was that some UI control access simply halted the execution (no exception was seen).
Under close examination (using WinDbg) I realized the controls were being updated from a ThreadPool thread, and a CrossThreadMessagingException was thrown.
My question is -- is there any good practice on how to circumvent such behavior?
It would be very cumbersome but also perhaps not possible to surround every code location that accesses UI controls with the Control.Invoke method.
How can i partition my code to "safe" code that shouldn't use Invoke, from one that should?

If the application is designed to be multithreaded, then cross-threading can occur and thus you need to check for it using InvokeRequired, and either have the method you are calling re-Invoke() itself on the UI thread, or throw an exception that will indicate code is being used improperly. Keep in mind that InvokeRequired will be false in certain circumstances (mainly when the window doesn't have a handle or is being/has been disposed); the best way to prevent these circumstances is to not start threads earlier in the window initialization process than the Load() event handler, and to handle the Closing() event by cancelling background threads created by the window and waiting for them to close.
If the application is not multithreaded (you are not setting up BackgroundWorkers, TPL operations, BeginInvoke()ing delegates or Start()ing threads), then it's not necessary. However, calls to InvokeRequired are pretty cheap (the logic behind it is basically a check that the WinAPI functions GetThreadId and GetWindowThreadProcessId return the same value), so if you anticipate the program being restructured to be multithreaded, the following patterns for called methods are simple enough to implement:
//no return value, no parameters; ShowWindow(), HideWindow(), etc
//Understand that many built-in control methods are not virtual and so you can't
//override them to do this; you must either hide them or ensure the caller is
//checking for cross-threading.
public void MyWindowMethod()
{
if(InvokeRequired)
this.Invoke(new Action(MyWindowMethod));
else
{
//main logic
}
}
//Input but no return; SetTitle("My Title")
public void MyWindowMethod2(string input)
{
if(InvokeRequired)
this.Invoke(new Action<string>(MyWindowMethod2), input);
else
{
//main logic
}
}
//inputs and outputs; custom methods, advanced graphics
public string MyWindowMethod3(string input)
{
if(InvokeRequired)
return (string)(this.Invoke(new Func<string, string>(MyWindowMethod3), input));
//No else required; the return makes it redundant
//main logic
}

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.

Marshalling Events Across Threads

I imagine this may be marked as repetitious and closed, but I cannot for the life of me find a clear, concise answer to this question. All the replies and resources deal almost exclusively with Windows Forms and utilizing pre-built utility classes such as BackgroundWorker. I would very much like to understand this concept at its core, so I can apply the fundamental knowledge to other threading implementations.
A simple example of what I would like to achieve:
//timer running on a seperate thread and raising events at set intervals
//incomplete, but functional, except for the cross-thread event raising
class Timer
{
//how often the Alarm event is raised
float _alarmInterval;
//stopwatch to keep time
Stopwatch _stopwatch;
//this Thread used to repeatedly check for events to raise
Thread _timerThread;
//used to pause the timer
bool _paused;
//used to determine Alarm event raises
float _timeOfLastAlarm = 0;
//this is the event I want to raise on the Main Thread
public event EventHandler Alarm;
//Constructor
public Timer(float alarmInterval)
{
_alarmInterval = alarmInterval;
_stopwatch = new Stopwatch();
_timerThread = new Thread(new ThreadStart(Initiate));
}
//toggles the Timer
//do I need to marshall this data back and forth as well? or is the
//_paused boolean in a shared data pool that both threads can access?
public void Pause()
{
_paused = (!_paused);
}
//little Helper to start the Stopwatch and loop over the Main method
void Initiate()
{
_stopwatch.Start();
while (true) Main();
}
//checks for Alarm events
void Main()
{
if (_paused && _stopwatch.IsRunning) _stopwatch.Stop();
if (!_paused && !_stopwatch.IsRunning) _stopwatch.Start();
if (_stopwatch.Elapsed.TotalSeconds > _timeOfLastAlarm)
{
_timeOfLastAlarm = _stopwatch.Elapsed.Seconds;
RaiseAlarm();
}
}
}
Two questions here; primarily, how do i get the event to the main thread to alert the interested parties of the Alarm event.
Secondarily, regarding the Pause() method, which will be called by an object running on the main thread; can i directly manipulate the Stopwatch that was created on the background thread by calling _stopwatch.start()/_stopwatch.stop(). If not, can the main thread adjust the _paused boolean as illustrated above such that the background thread can then see the new value of _paused and use it?
I swear, I've done my research, but these (fundamental and critical) details have not made themselves clear to me yet.
Disclaimer: I am aware that there are classes available that will provide the exact particular functionality that I am describing in my Timer class. (In fact, I believe the class is called just that, Threading.Timer) However, my question is not an attempt to help me implement the Timer class itself, rather understand how to execute the concepts that drive it.
Note: im writing this here because theres not enough space on comments, this is of course not a complete, nor half a complete answer:
I've always used Events to signal unrelated code to do something, so that was how I described my intent. Forgive me though, I'm not sure I see the difference between marshaling and event versus marshaling another type of data (signal).
Conceptually both can be treated as events. The difference between using provided sync/signalining objects and trying to implement something like this by urself, is who and how gets the job done.
An event in .net is just a delegate, a list of pointers to methods that should be executed when the provider of the event fires it.
What youre talking about (marshalling the event), if i understand you correctly, is sharing the event object when something happens, while the concept of signalig usually talks about an object which is shared to start with, and both threads "know" something happened by checking its state either manualy or automatily (relying on provided tools by both .net and windows).
In the most basic scenario, you can implement such a signaling concept by using a boolean variable, with one thread constantly looping to check if the value of the boolean is true, and another setting to such, as a way to signal something happend. The different signaling tools provided by .NET do this in a less resource-wasting maner, by also not executing the waiting thread, as long as theres no signal (the boolean equals to false), but conceptually, it is the same idea.
You cannot magically execute code on an existing thread.
Instead, you need the existing thread to explicitly execute your code, using a thread-safe data structure to tell it what to do.
This is how Control.Invoke works (which is in turn how BackgroundWorker works).
WiinForms runs a message loop in Application.Run() which looks roughly like this:
while(true) {
var message = GetMessage(); //Windows API call
ProcessMessage(message);
}
Control.Invoke() sends a Windows message (using thread-safe message passing code within Windows) telling it to run your delegate. ProcessMessage (which executes on the UI thread) will catch that message and execute the delegate.
If you want to do this yourself, you will need to write your own loop. You can use the new thread-safe Producer-Consumer collections in .Net 4.0 for this, or you can use a delegate field (with Interlocked.CompareExchange) and an AutoResetEvent and do it yourself.

Updating UI after running background work with parallel.Invoke

I'm running heavvy background work with Parallel.Invoke, after all processing has completed I return the method, return again, call a next method to utilize the calculated data I get the error:
Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on.
But I already returned from the threads that where created by Parallel.Invoke to the one that called it in the first place. Is it normal that control does not revert to the thread where it started? And how can I assure that this does happen?
Code:
public void TopMethod()
{
Calculate(4);
UpdateGui();
}
public void Calculate(int depth)
{
Recursive(depth);
}
public void Recursive(int depth)
{
if (depth > 0)
System.Threading.Tasks.Parallel.Invoke(
delegate { Recursive(depth - 1); });
}
public void UpdateGui()
{
CalculateOhter(); // Works fine.
controlElement.Focus(); // Causes exception
}
Edits:
I know about Control.Invoke But this would be an ugly solution (don't want to store a delegate in every control) and the program needs to wait for all computations to complete before it can continue. So it would be better if I could somehow force control to return to the thread that I started out with in the first place.
You need to access a control/window from the thread that created that control. Use Control.Invoke and Control.InvokeRequired.
The horrible way to do is to set Control.CheckForIllegalCrossThreadCalls to false. It should get rid of your error, but it is not good design.
The problem with that occurs when a thread other than the creating thread of a control tries to access one of that control's methods or properties, it often leads to unpredictable results.
The example for Control.Invoke involves storing a Delegate, can this be done without storing a delegate for every control? So passing the method I need to call as an argument to the Invoke call (tried this but cannot get it to work).
The program needs to wait for all computations to complete before it can continue so it would be better if I could somehow force control to return to the thread that I started out with in the first place.
I don't understand why this does not happen at default, why does it not just return to the thread it started with when everything is complete?
Solved it, turns out I created a seperate thread to call the given code in the first place, kinda stupid :P

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.

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

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;
}
}
}

Categories