3

When I want to update controls across threads this is how I generally end up doing it:

this.Invoke((MethodInvoker)delegate { SomeProcedure(); });

The suggested way to do it is actually to call the invoker for the specific control you want to update, but 99% of the time the form (i.e. 'this' in my example) and the control are going to have been created on the same thread so I really like doing this way for simplicity's sake.

I was thinking though that it would be nice if I just had a PostSharp aspect to put on top of SomeProcedure that would wrap it in that mess of a statement for me.

And go... (oh yeah, 100 bonus pts to first usable answer :)

Brandon Moore
  • 8,590
  • 15
  • 65
  • 120
  • I'm not entirely sure I understand _exactly_ what you want, especially with regards to your second paragraph. But does PostSharp's example code help at all? http://www.sharpcrafters.com/solutions/multithreading – Chris Sinclair Jun 25 '12 at 03:22

1 Answers1

8

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();
    }
}
Chris Sinclair
  • 22,858
  • 3
  • 52
  • 93