开发者

How to invoke on the UI thread of a WinForm Component?

开发者 https://www.devze.com 2023-01-21 17:48 出处:网络
I\'m coding a WinForm component where I start a Task to do the actual processing and trap the exception on a continuation. From there I want to show the exception message on a UI element.

I'm coding a WinForm component where I start a Task to do the actual processing and trap the exception on a continuation. From there I want to show the exception message on a UI element.

Task myTask = Task.Factory.StartNew (() => SomeMethod(someArgs));
myTask.ContinueWith (antecedant => uiTextBox.Text = antecedant.Exception.Message,
                     TaskContinuationOptions.OnlyOnFaulted);

Now I get a cross-thread exception because the task is trying to update a UI element from a, obviously, non UI thread.

H开发者_如何学Cowever, there is no Invoke or BeginInvoke defined in the Component class.

How to proceed from here?


UPDATE

Also, please note that Invoke/BeginInvoke/InvokeRequired are not available from my Component-derived class since Component doesn't provide them.


You could just add a property to your component, allows the client to set a form reference that you can use to call its BeginInvoke() method.

That can be done automatically as well, preferable so nobody can forget. It requires a bit of design time magic that's fairly impenetrable. I didn't come up with this by myself, I got it from the ErrorProvider component. Trusted source and all that. Paste this into your component source code:

using System.Windows.Forms;
using System.ComponentModel.Design;
...
    [Browsable(false)]
    public Form ParentForm { get; set; }

    public override ISite Site {
        set {
            // Runs at design time, ensures designer initializes ParentForm
            base.Site = value;
            if (value != null) {
                IDesignerHost service = value.GetService(typeof(IDesignerHost)) as IDesignerHost;
                if (service != null) this.ParentForm = service.RootComponent as Form;
            }
        }
    }

The designer automatically sets the ParentForm property when the user drops your component on a form. Use ParentForm.BeginInvoke().


You can use delegates to do this.

    delegate void UpdateStatusDelegate (string value);


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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号