Invoke(Delegate)

Invoke(Delegate)

The answer to this question lies in how C# Controls work

Controls in Windows Forms are bound to a specific thread and are not
thread safe. Therefore, if you are calling a control's method from a
different thread, you must use one of the control's invoke methods to
marshal the call to the proper thread. This property can be used to
determine if you must call an invoke method, which can be useful if
you do not know what thread owns a control.

From Control.InvokeRequired

Effectively, what Invoke does is ensure that the code you are calling occurs on the thread that the control "lives on" effectively preventing cross threaded exceptions.

From a historical perspective, in .Net 1.1, this was actually allowed. What it meant is that you could try and execute code on the "GUI" thread from any background thread and this would mostly work. Sometimes it would just cause your app to exit because you were effectively interrupting the GUI thread while it was doing something else. This is the Cross Threaded Exception - imagine trying to update a TextBox while the GUI is painting something else.

  • Which action takes priority?
  • Is it even possible for both to happen at once?
  • What happens to all of the other commands the GUI needs to run?

Effectively, you are interrupting a queue, which can have lots of unforeseen consequences. Invoke is effectively the "polite" way of getting what you want to do into that queue, and this rule was enforced from .Net 2.0 onward via a thrown InvalidOperationException.

To understand what is actually going on behind the scenes, and what is meant by "GUI Thread", it's useful to understand what a Message Pump or Message Loop is.

This is actually already answered in the question "What is a Message Pump" and is recommended reading for understanding the actual mechanism that you are tying into when interacting with controls.

Other reading you may find useful includes:

What's up with Begin Invoke

One of the cardinal rules of Windows GUI programming is that only the
thread that created a control can access and/or modify its contents
(except for a few documented exceptions). Try doing it from any other
thread and you'll get unpredictable behavior ranging from deadlock, to
exceptions to a half updated UI. The right way then to update a
control from another thread is to post an appropriate message to the
application message queue. When the message pump gets around to
executing that message, the control will get updated, on the same
thread that created it (remember, the message pump runs on the main
thread).

and, for a more code heavy overview with a representative sample:

Invalid Cross-thread Operations

// the canonical form (C# consumer)

public delegate void ControlStringConsumer(Control control, string text); // defines a delegate type

public void SetText(Control control, string text) {
if (control.InvokeRequired) {
control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text}); // invoking itself
} else {
control.Text=text; // the "functional part", executing only on the main thread
}
}

Once you have an appreciation for InvokeRequired, you may wish to consider using an extension method for wrapping these calls up. This is ably covered in the Stack Overflow question Cleaning Up Code Littered with Invoke Required.

There is also a further write up of what happened historically that may be of interest.

Difference between Delegate.Invoke and Delegate()

The delTest() form is a compiler helper, underneath it is really a call to Invoke().

C# : this.Invoke((MethodInvoker)delegate

Strange that no one has answered this.

Lets take it in pieces:

this.Invoke: This is a synchronization mechanism, contained in all controls. All graphic/GUI updates, must only be executed from the GUI thread. (This is most likely the main thread.) So if you have other threads (eg. worker threads, async functions etc.) that will result in GUI updates, you need to use the Invoke. Otherwise the program will blow up.

delegate{ ... }: This is a anonymous function. You can think of it as "creating a function on the fly". (Instead of finding a space in the code, create function name, arguments etc.)

(MethodInvoker): The MethodInvoker is just the name of the delegate, that Invoke is expecting. Eg. Invoke expects to be given a function, with the same signature as the "MethodInvoker" function.

What happens, is that Invoke is given a function pointer. It wakes up the GUI thread through a mutex and tells it to executes the function (through the function pointer). The parent thread then waits for the GUI thread to finish the execution. And it's done.

Invoke delegate method name with parameter

Try calling it this way:

lblMessage.Invoke((Action)(() => SetMessage(value)));

Then you can also avoid creating the private UpdateMessageDelegate delegate.

Delegate invoke

You can not touch any UI element from any threads other than the thread that owns the object. To achieve this you can wrap the call in a Invoke method like this:

delegate void UpdateStatusDelegate (string value);

private void UpdateStatus(string value)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new UpdateStatusDelegate(UpdateStatus), new object[]{value});
return;
}
// Must be on the UI thread if we've got this far
statusIndicator.Text = value;
}

in WPF world, you could get the same thing by using Dispatcher.Invoke method.

Where is declaration of invoke method in Delegate class?

When you create a delegate, the compiler at compile time generates a class inheriting from MulticastDelegate, adding three methods to the class: BeginInvoke, EndInvoke and Invoke. You can easily see it using using ILSpy and the likes.

That is why you cant see it while looking in the Delegate class

This is what MSDN has to say:

MulticastDelegate is a special class. Compilers and other tools can derive from this class, but you cannot derive from it explicitly. The same is true of the Delegate class.

In addition to the methods that delegate types inherit from MulticastDelegate, the common language runtime provides two special methods: BeginInvoke and EndInvoke.

A MulticastDelegate has a linked list of delegates, called an invocation list, consisting of one or more elements. When a multicast delegate is invoked, the delegates in the invocation list are called synchronously in the order in which they appear. If an error occurs during execution of the list then an exception is thrown


Parameterized Action Invoke Delegate

There's no need to include the delegate cast in the actual call.

The parameters go into the 2nd argument of the Invoke method, being a params object array, here containing control and text.

public void SetControlText(Control control, string text)
=> this.Invoke((Action<Control, string>)((ctrl, txt) => ctrl.Text = txt), control, text);


Related Topics



Leave a reply



Submit