C# 在另一个线程中运行任务,然后向主线程报告

C# 在另一个线程中运行任务,然后向主线程报告,c#,multithreading,user-interface,C#,Multithreading,User Interface,我使用多个按钮的用户界面,我需要在点击按钮时启动后台任务,并在任务完成后向主线程+更新用户界面报告 这是我当前代码的一部分: private void button1Click(object sender, EventArgs e) { button1.Text = "Starting"; button1.Enabled = false; button1Worker.RunWorkerAsync(); } private

我使用多个按钮的用户界面,我需要在点击按钮时启动后台任务,并在任务完成后向主线程+更新用户界面报告

这是我当前代码的一部分:

private void button1Click(object sender, EventArgs e)
    {
        button1.Text = "Starting";
        button1.Enabled = false;
        button1Worker.RunWorkerAsync();
    }

    private void button1worker_DoWork(object sender, DoWorkEventArgs e)
    {
        toolStarter.startTool("button1");
    }

    private void button1worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        button1.Text = "Autoruns";
        button1.Enabled = true;
    }
此解决方案按照预期/预期工作,但是相同的代码在15个不同的按钮上重复,这对我来说似乎是错误的

你能推荐其他方法做同样的事情吗


我确实尝试了
ThreadPool
队列,但在任务完成后没有更新UI。

您可以改为通过async/await执行此操作,这简化了代码并消除了对后台工作人员的需要:

如果您的按钮都在执行相同的操作,但仅更改字符串,则可以重构该按钮以支持该操作:

private async Task ExecuteButton(Button button, string toolName)
{
     button.Text = "Starting";
     button.Enabled = false;
     await Task.Run(() => toolStarter.startTool(toolName));
     button.Text = "Autoruns";
     button.Enabled = true;  
}

private async void button1Click(object sender, EventArgs e)
{
     await ExecuteButton(button1, "button1");
     // Do any other specific stuff for after here
}

// Use for other buttons as needed
private async void button2Click(object sender, EventArgs e)
{
     await ExecuteButton(button2, "button2");
}

谢谢,这真是太棒了!
private async Task ExecuteButton(Button button, string toolName)
{
     button.Text = "Starting";
     button.Enabled = false;
     await Task.Run(() => toolStarter.startTool(toolName));
     button.Text = "Autoruns";
     button.Enabled = true;  
}

private async void button1Click(object sender, EventArgs e)
{
     await ExecuteButton(button1, "button1");
     // Do any other specific stuff for after here
}

// Use for other buttons as needed
private async void button2Click(object sender, EventArgs e)
{
     await ExecuteButton(button2, "button2");
}
// This is your helper class that actually does the work
public class ToolStarter 
{
    public void startTool(string name)
    {
        // Put your switch statement here to decide what work to do
    }
}

public class ButtonWorker
{
    private Button button;
    private ToolStarter toolStarter;

    public ButtonWorker(Button button, ToolStarter toolStarter)
    {
        this.button = button;
        this.toolStarter = toolStarter;

        this.button.Enabled = false;
        this.button.Text = "Starting";

        ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
    }

    private void DoWork(object state)
    {
        this.toolStarter.startTool(button.Name);

        // Pass control back to the UI thread so you can update your 
        // button text and enabled/status
        this.button.Invoke(new Action(() => 
        {
            this.button.Text = "Autoruns";
            this.button.Enabled = true;
        }));
    }
}

// This is just showing you how to use the ButtonWorker
public class ButtonWorkerTest
{
    public ButtonWorkerTest()
    {
        var btn1 = new Button { Name = "button1" };
        var btn2 = new Button { Name = "button2" }; 
        var toolstarter = new ToolStarter(); // This is your class

        var worker1 = new ButtonWorker(btn1, toolstarter);
        var worker2 = new ButtonWorker(btn2, toolstarter);
    }
}