简体   繁体   中英

Run Method from a secondary thread on the main thread in C#?

I am using VSTO, and I would like to have a progress bar for a task that operates on the Excel model (getting and setting rages) via COM Interop. When doing any task that operates on the Excel model, it is very very highly recommended to only do so from the main thread (there are many posts that discuss this).

My problem is that I would like to have a progress bar (that exists on a secondary thread) and I would like to be able to start my task (on the main thread) when the progress bar loads. Is there some way to queue a function to execute on the main thread from a secondary thread? If not, is there some other way I can set this up?

My source is below:

abstract class BaseProgressTask
{
    private ProgressForm _form;
    public volatile bool CancelPending;

    private void ShowProgressForm()
    {
        _form = new ProgressForm(this) { StartPosition = FormStartPosition.CenterScreen };
        _form.ShowDialog();
    }

    public BaseProgressTask()
    {
        ThreadStart startDelegate = ShowProgressForm;
        Thread thread = new Thread(startDelegate) { Priority = ThreadPriority.Highest };
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
    }

    public abstract void Run();

    protected void ReportProgress(int percent)
    {
        _form.BeginInvoke(new Action(() => _form.SetProgress(percent)));
    }

    protected void CloseForm()
    {
        _form.BeginInvoke(new Action(() => _form.Close()));
    }
}

public partial class ProgressForm : Form
{
    private BaseProgressTask _task;
    public ProgressForm(BaseProgressTask task)
    {
        InitializeComponent();
        _task = task;
    }

    private void btnCancel_Click(object sender, EventArgs e)
    {
        _task.CancelPending = true;
        lblStatus.Text = "Cancelling...";
    }

    public void SetProgress(int percent)
    {
        myProgressBar.Value = percent;
    }

    private void ProgressForm_Load(object sender, EventArgs e)
    {
        //Any way to do this?
        ExecuteOnMainThread(_task.Run);
    }
}

You may consider using the BackgroundWorker component instead. It executes an operation on a separate thread and allows to report a progress in a more convinient way using event handlers. See How to: Use a Background Worker and Walkthrough: Multithreading with the BackgroundWorker Component (C# and Visual Basic) for more information.

The SendMessage function from Windows API can be used to run an action on the main thread.

In case if your main thread is a form, you can handle it with this short code:

 if (InvokeRequired)
 {
     this.Invoke(new Action(() => MyFunction()));
     return;
 }

or .NET 2.0

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM