---
# System prepended metadata

title: '[C# WinForm] - Use a background thread to observe the behavior of the cancel button'

---

GitHub: [https://github.com/CarterWu-M/CS-WinForms_back-thread]

This example code uses a start button to call testTask(), which displays a number in the textbox every second. The cancel button uses CancellationTokenSource() to trigger a cancel event.
![image](https://hackmd.io/_uploads/SJlKIrsl1l.png)

---
### Without Task.Run()
---
```C#=
namespace background_thread
{
    public partial class Form1 : Form
    {
        private CancellationTokenSource _cancellationTokenSource;
        
        public Form1()
        {
            InitializeComponent();
        }
        
        private void btnStart_Click(object sender, EventArgs e)
        {
            testTask();
        }
        
        private void btnStop_Click(object sender, EventArgs e)
        {
            this._cancellationTokenSource?.Cancel();
        }
        
        private void testTask()
        {
            this._cancellationTokenSource?.Dispose();
            this._cancellationTokenSource = new CancellationTokenSource();

            try
            {
                for (uint i = 0; 10 > i; i++)
                {
                    Thread.Sleep(1000);
                    txt1.Text = i.ToString();
                    txt1.Refresh();
                    this._cancellationTokenSource.Token.ThrowIfCancellationRequested();
                }
            }
            catch (OperationCanceledException)
            {
                MessageBox.Show("Task has been Cancend!");
            }
        }
    }
}
```
![image](https://hackmd.io/_uploads/HkS3UHolyx.png)
![image](https://hackmd.io/_uploads/S1L6UHslkl.png)
During the testTask() operation, you'll notice that you can't click the cancel button or move the window until testTask() has finshed.

Because testTask() uses synchronous code, it blocks the UI, preventing the cencel button from being triggered.
![image](https://hackmd.io/_uploads/SkVkqPsg1g.png)

---
### With Task.Run()
---
```C#=
private void btnStart_Click(object sender, EventArgs e)
{
    //Task.Run(): Create a background thread to run testTask()
    Task.Run(() => {
        testTask();
    });
}

private void testTask()
{
    this._cancellationTokenSource?.Dispose();
    this._cancellationTokenSource = new CancellationTokenSource();

    try
    {
        for (uint i = 0; 10 > i; i++)
        {
            Thread.Sleep(1000);
            //When accessing the UI in a background thread,
            //you need to use .Invoke(new Action())
            txt1.Invoke(new Action(() => txt1.Text = i.ToString()));
            txt1.Invoke(new Action(() => txt1.Refresh()));
            this._cancellationTokenSource.Token.ThrowIfCancellationRequested();
        }
    }
    catch (OperationCanceledException)
    {
        MessageBox.Show("Task has been Cancend!");
    }
}
```
![image](https://hackmd.io/_uploads/HyeNxRSjlJl.png)
![image](https://hackmd.io/_uploads/H1pWAHsxJx.png)
During the testTask() operation, you'll notice that you can click the cancel button because Task.Run() creates a background theread for testTask(), making it asynchronous.

![image](https://hackmd.io/_uploads/SkTPiwsg1e.png)


---
### With await Task.Run()
---
```C#=
private async void btnStart_Click(object sender, EventArgs e)
{
    btnStart.BackColor = Color.LightGray;
    btnCancel.BackColor = Color.LightBlue;

    //await: wait for testTask() to finished
    await Task.Run(() => {
        testTask();
    });

    btnStart.BackColor = Color.LightGreen;
    btnCancel.BackColor = Color.LightGray;
}
```
![image](https://hackmd.io/_uploads/HyH4cLjgkl.png)
![image](https://hackmd.io/_uploads/Hy2HqLol1g.png)
Since Task.Run() is asynchronous, if you have something to do after testTask(), you can add await before Task.Run()

![image](https://hackmd.io/_uploads/SJKLnvse1e.png)

