Cleanest Way to Invoke Cross-Thread Events

Cleanest Way to Invoke Cross-Thread Events

A couple of observations:

  • Don't create simple delegates explicitly in code like that unless you're pre-2.0 so you could use:
   BeginInvoke(new EventHandler<CoolObjectEventArgs>(mCoolObject_CoolEvent), 
sender,
args);
  • Also you don't need to create and populate the object array because the args parameter is a "params" type so you can just pass in the list.

  • I would probably favor Invoke over BeginInvoke as the latter will result in the code being called asynchronously which may or may not be what you're after but would make handling subsequent exceptions difficult to propagate without a call to EndInvoke. What would happen is that your app will end up getting a TargetInvocationException instead.

Thread-safe events - is this a clean way?

State of the art is using await. If that is not possible here, at least simplify the code to a single Invoke call. It is not needed to invoke on each control, just invoke anywhere on the UI thread.

The InvokeRequired check should not be required because you should know on what thread the event is raised.

In any case duplicating logic such as "Current state: " + e.Step is really a bad idea and I would fail this in a code review no matter what.

The presence of Application.DoEvents is a really bad sign. Probably a misunderstanding because it only makes sense to call it on the UI thread, but why Invoke when already on the UI thread?! Looks like a contradiction.

lstStatus.Refresh(); is also a misunderstanding, probably superstitious. Controls refresh automatically (if you allow for event processing).

Cross thread operation while working event raised by other object

UI controls can only be updated from UI thread.
If you are working with WinForms you should do:

mycontrol.Invoke((MethodInvoker)(() =>
{
mycontrol.Text="some text";
}));

And if you are in WPF then you should use the dispatcher:

myControl.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => myControl.Text = ""));

Sending an event from a thread to a UI

H/T to S.A. Parkhid for this link.

Here is the solution: modify the method OnConnected to the following:

    public void OnConnected(string str)
{
if (textBox1.InvokeRequired)
{
var d = new TestEvent.clsConnect(OnConnected);
textBox1.Invoke(d, new object[] { str });
}
else
{
textBox1.Text = str;
}
}

Avoiding the woes of Invoke/BeginInvoke in cross-thread WinForm event handling?

Your scenario, as described, neatly fits BackgroundWorker - why not just use that? Your requirements for a solution are way too generic, and rather unreasonable - I doubt there is any solution that would satisfy them all.

Cross Thread Operation - Invoked function calls another function C#

You need to .Invoke onto the main thread to change any controls.

Image image;
if (this.currColor == Color.Blue)
image = bluePencil;
else
image = redPencil;

this.Invoke(new MethodInvoker(() => pencils[currIndex--].Image = image));

The => is the syntax for a lambda (called anonymous method in other languages). Think about it as a one-line function.

() => pencils[currIndex--].Image = image

is the same as:

void SetImage(Image image, ref int currIndex) {
pencils[currIndex--].Image = image;
}

MethodInvoker provides a simple delegate that is used to invoke a method with a void parameter list

How to write a PostSharp Invoke aspect to simplify cross thread control updates

I haven't programmed thread access before on WinForms, but I have done it with PostSharp + Silverlight. So with a bit of googling, I'll give it a shot. No guarantees that it works though!

[Serializable]
public class OnGuiThreadAttribute : MethodInterceptionAspect
{
private static Control MainControl;

//or internal visibility if you prefer
public static void RegisterMainControl(Control mainControl)
{
MainControl = mainControl;
}

public override void OnInvoke(MethodInterceptionArgs eventArgs)
{
if (MainControl.InvokeRequired)
MainControl.BeginInvoke(eventArgs.Proceed);
else
eventArgs.Proceed();
}
}

And the idea is at the start of your application, register your main/root control with the attribute. Then any method you want to ensure runs on the main thread, just decorate with [OnGuiThread]. If it's already on the main thread, it just runs the method. If it's not, it will promote the method call as a delegate to the main thread asynchronously.

EDIT: I just figured out (it's late) that you're asking to use the specific invoking method for the target control you're using. Assuming that you decorate instance methods on subclasses for your controls:

[Serializable]
public class OnGuiThreadAttribute : MethodInterceptionAspect
{
public override void OnInvoke(MethodInterceptionArgs eventArgs)
{
//you may want to change this line to more gracefully check
//if "Instance" is a Control
Control targetControl = (Control)eventArgs.Instance;

if (targetControl.InvokeRequired)
targetControl.BeginInvoke(eventArgs.Proceed);
else
eventArgs.Proceed();
}
}


Related Topics



Leave a reply



Submit