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

时间:2014-08-12 18:48:14

标签: c# multithreading user-interface

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

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

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。

2 个答案:

答案 0 :(得分:2)

您可以通过async / await来实现,这样可以简化代码并消除对后台工作人员的需求:

private async void button1Click(object sender, EventArgs e)
{
     button1.Text = "Starting";
     button1.Enabled = false;
     await Task.Run(() => toolStarter.startTool("button1"));
     button1.Text = "Autoruns";
     button1.Enabled = true;  
}

如果您的按钮都在执行相同的操作,只更改了字符串,您可以重构它以支持:

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

答案 1 :(得分:0)

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