0

It is necessary to execute the methods sequentially in the order they were started, but without stopping the UI. In the example that I made, the operations are performed asynchronously, which leads to incorrect entries in the ListNumber list.

 public Form1()
    {
        InitializeComponent();
        ListNumber = new List<string>();
    }
    List<string> ListNumber { get; set; }
    private async void button1_Click(object sender, EventArgs e)
    {
        textBox1.Text = await Task.Run(() => MessageAsync());
    }
    private async Task<string> MessageAsync()
    {
        var concat = "";
        await NumberAsync();
        foreach (string number in ListNumber)
        {
            concat += number + ", ";
        }
        return concat;
    }

    private async Task NumberAsync()
    {
        for(int i = 0; i < 30; i++)
        {
            ListNumber.Add(i.ToString());
            await Task.Delay(300);
        }
        
    }

If you quickly click on the button, the calling method gives the following result: the result of the program

  • Have you tried to disable the button until the first execution is done? Or does that not work for you? – Xerillio Aug 10 '22 at 17:10
  • so you want to schedule as many tasks as the number of times the button was pressed and keep the button enabled ? – alexm Aug 10 '22 at 23:30
  • Possibly related: [Task sequencing and re-entracy](https://stackoverflow.com/questions/21424084/task-sequencing-and-re-entracy) – Theodor Zoulias Aug 10 '22 at 23:37
  • @alexm Yes, so that each task works to the end and the next one just begins. For example, two quick clicks and ListNumber is written from 0 to 29 and then again from 0 to 29. – Равиль Мещеров Aug 11 '22 at 08:45

1 Answers1

0

Xerillio's proposed solution does work as long as you don't expect the button to be responsive after be pressed:

private async void button1_Click(object sender, EventArgs e)
{
    button1.IsEnabled = false;
    textBox1.Text = await Task.Run(() => MessageAsync());
    button1.IsEnabled = true;
}

If you need to be able to use the button while your task is running, or in other words you expect several things to need access to the ListNumber resource you need to design a system for controlling access to that resource. Only allowing one producer to add values to the list at a time for instance would be a method but it all depends on what behavior you want to see.

Below is a working version which controls access to the LisNumber object using a semaphore.

    public MainWindow()
    {         
        InitializeComponent();
        ListNumber = new List<string>();
        semaphore = new SemaphoreSlim(1, 1);
    }
    SemaphoreSlim semaphore;
    List<string> ListNumber { get; set; }

    private async void button1_Click(object sender, EventArgs e)
    {
        await NumberAsync();
        textBox1.Text = await Message();
    }

    private async Task<string> Message()
    {
        await semaphore.WaitAsync();
        var concat = "";
        foreach (string number in ListNumber)
        {
            concat += number + ", ";
        }
        semaphore.Release();
        return concat;
    }

    private async Task NumberAsync()
    {
        await semaphore.WaitAsync();
        for (int i = 0; i < 30; i++)
        {
            ListNumber.Add(i.ToString());
            await Task.Delay(300);
        }
        semaphore.Release();
    }

You could also just wrap the button call in the semaphore if you wanted:

private async void button1_Click(object sender, EventArgs e)
{
    await semaphore.WaitAsync();
    await NumberAsync();
    textBox1.Text = await Message();
    semaphore.Release();
}
  • I'm looking for a way in which access to the button was always and tasks when the button was pressed were added to the queue and executed in the order when they were called.To keep the order of entries in ListNumber. – Равиль Мещеров Aug 11 '22 at 03:50
  • As I mentioned in my answer you are then looking for an access control method for the resource. Tasks added to the a queue could be a method if it works for your use case. – Erik Kinstler Aug 11 '22 at 12:51
  • yes, exactly, how to make the button always available, and the tasks launched by this button are executed sequentially? – Равиль Мещеров Aug 11 '22 at 18:33
  • It is very difficult to tell you how to solve this problem because it depends entirely on your use case and how you want to solve the problem. I edit my answer to provide you one some options, but really you need to explore what the correct solution is on your own. – Erik Kinstler Aug 12 '22 at 20:28