1

I have a program that checks what is the user reaction time based on speed he clicks on the button when it changes to green. I would like the function that is working after clicking the button to run in the background.

I though by using Task it will make it asynchronously but it seems to not be the case. I understand that there is an await and probably I should make it somehow return to place it was called but I have a problem finding the solution.

My code so far looks like this

public partial class Reaction : Form
{
    Stopwatch timer;
    bool start = false;
    public Reaction()
    {
        InitializeComponent();
        button1.Text = "START";
        button1.BackColor = Color.Red;

    }

    public async Task Test()
    {
        if (start)
        {
            timer.Stop();
            TimeSpan timespan = timer.Elapsed;
            string timeString = String.Format("{0:00}:{1:00}:{2:00}", timespan.Minutes, timespan.Seconds, timespan.Milliseconds / 10);
            MessageBox.Show(timeString);
            button1.BackColor = Color.Red;
            button1.Text = "START";
            start = false;
        }
        else
        {
            Random rnd = new Random();
            int number = rnd.Next(1, 10000);
            System.Threading.Thread.Sleep(3000 + number);
            timer = Stopwatch.StartNew();
            button1.BackColor = Color.Green;
            button1.Text = "CLICK";
            start = true;
        }
    }

    private async void button1_Click(object sender, EventArgs e)
    {

        button1.BackColor = Color.Red;
        button1.Text = "Dont click";
        await Test();
    }
}
phoenix
  • 365
  • 1
  • 4
  • 15
  • Why don't you run the "background" code in a new thread? Like this: Thread T = new thread(test); T.start(); – Taco2 Apr 11 '17 at 17:57
  • 1
    you should use Task.Delay(1000); instead of Thread.Sleep – Joshua Duxbury Apr 11 '17 at 17:58
  • Using Task.Delay(1000); does not solve the problem. It's just another wait to "wait" – Taco2 Apr 11 '17 at 17:59
  • The compiler already gives you a warning telling you exactly what's wrong here. See marked duplicate for what your mistake is. That said, there's nothing about your scenario that seems to justify using a separate async method, and certainly not `Task.Run()` (as proposed in the one answer below). You could put everything in the `Click` event handler, make that method `async`, and use `await Task.Delay()` instead of `Thread.Sleep()` for the timing aspect. – Peter Duniho Apr 11 '17 at 18:13
  • @Taco2: actually, using `Task.Delay()` would in fact solve the problem, because it would change the synchronous method into an asynchronous method. It would get rid of the compiler warning that the OP should be seeing with the code they have now, and would let the timing part of the code run asynchronously. – Peter Duniho Apr 11 '17 at 18:17

1 Answers1

0

Based on the comments I edited the post to reflect more closely what you were asking for. Remove the async and await in the button's click event and replace the System.Threading.Thread.Sleep(... with await Task.Delay(... This way you will not have to use BeginInvoke on button1 and the only thing on a separate thread will be the Task.Delay(...

The UI will become responsive during the Task.Delay(... and then resume where it left off when the delay is finished.

public partial class Reaction : Form
{
    Stopwatch timer;
    bool start = false;
    public Reaction()
    {
        ...
    }

    public async Task Test()
    {
        if (start)
        {
            ...
        }
        else
        {
            Random rnd = new Random();
            int number = rnd.Next(1, 10000);

            // Replace Thread.Sleep with Task.Delay
            await Task.Delay(3000 + number);

            timer = Stopwatch.StartNew();
            button1.BackColor = Color.Green;
            button1.Text = "CLICK";
            start = true;
        }
    }

    // Make button1_Click not async and remove await
    private void button1_Click(object sender, EventArgs e)
    {
        button1.BackColor = Color.Red;
        button1.Text = "Dont click";
        Test();
    }
}
Kyle B
  • 2,328
  • 1
  • 23
  • 39
  • while changing button text in button1.Text = "CLICK"; I get an access from diffrent thread error – phoenix Apr 11 '17 at 18:13
  • 1
    @feni000: yes, you do. Because the above answer just takes your original code and wraps it in a whole new problem. You don't need `Task.Run()` here. You need `await Task.Delay()` in your original method, or just put all that code in the `button1_Click()` method. – Peter Duniho Apr 11 '17 at 18:15
  • Although this could work, `async/await` provides more elegant solution w/o the need of `Task.Run` as @PeterDuniho mentioned. – Ivan Stoev Apr 11 '17 at 18:26
  • I see your point now @PeterDuniho, I misread the question, Task.Delay would be better. – Kyle B Apr 11 '17 at 18:43