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

爷,独闯天下 提交于 2019-12-02 21:15:24

问题


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.

However, 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.


回答1:


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().




回答2:


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


来源:https://stackoverflow.com/questions/4018263/how-to-invoke-on-the-ui-thread-of-a-winform-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!