0

I am using UI with multiple buttons and I need to start background task on button click and report back to main thread + update UI when the task is finished.

This is currently part of my code:

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

This solution works as intended / expected, however the same code is repeated for 15 different buttons and that seem to be wrong to me.

Can you recommend some other way to do the same thing?

I did try ThreadPool queue but did not manage to update UI after task finished.

xDaevax
  • 2,012
  • 2
  • 25
  • 36
stkxchng
  • 65
  • 5
  • 26

2 Answers2

2

You can do this via async/await instead, which simplifies the code and eliminates the need for the background worker(s):

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

If your buttons are all doing the same operation, with only the string changing, you can refactor this out to support that:

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");
}
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
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);
    }
}
Jon
  • 3,230
  • 1
  • 16
  • 28