1

I have a pretty heavy loop in my button click event that takes about 1-2 minutes to complete (loops around 50000 times):

while (continue)
{
    if (xlRange.Cells[i, j].Value2 == null)
        continue = false;
    else
    {
        pbar.PerformStep();
        string key = xlRange.Cells[i, j].Value2.ToString();
        Random r = new Random();
        bool ok = r.Next(100) <= 2 ? false : true;
        if (!ok)
        {
            this.dataGridView1.Rows.Add(x + 1, key);
            x++;
            groupBox2.Text = "Error (" + x + ")";
        }
        i++;
    }
}

The loop locks the UI and it is not possible to press any button or even move the window.

Can't move the window while looping

How can I do this asynchronous or not blocking in a 'pro' way? Thanks.

8
  • Does the web service that you're calling offer asynchronous methods? If so, use await SomeMethodAsync();. Commented Jul 23, 2019 at 10:04
  • @AhmedAbdelhameed the problem is not in the web service call, in fact it isn't implemented yet. The loop itself takes too many time. Commented Jul 23, 2019 at 10:15
  • That's not true. A loop in and of itself doesn't take time (since it doesn't perform anything). A loop repeating 50,000 times adding two integers would take a few milliseconds, for example. So, what matter is the work that's being carried out inside the loop (and repeated by the loop). How much time it takes affects how much the loop would take to complete. Commented Jul 23, 2019 at 10:19
  • You could run the code asynchronously and wrap the update of the progress bar into a call to the Invoke() method, example is here stackoverflow.com/questions/12955533/…. Commented Jul 23, 2019 at 10:21
  • 1
    You could put the code into a Background worker, or use a Task. learn.microsoft.com/en-us/dotnet/api/…. learn.microsoft.com/en-us/dotnet/api/… Commented Jul 23, 2019 at 10:30

2 Answers 2

3

How about using the thread?

new Thread(() =>
{
    while (continue)
    {
        if (xlRange.Cells[i, j].Value2 == null)
            continue = false;
        else
        {
            Invoke(new Action(() =>
            {
                pbar.PerformStep();
            }));
            string key = xlRange.Cells[i, j].Value2.ToString();
            Random r = new Random();
            bool ok = r.Next(100) <= 2 ? false : true;
            if (!ok)
            {
                Invoke(new Action(() =>
                {
                    this.dataGridView1.Rows.Add(x + 1, key);
                }));
                x++;
                Invoke(new Action(() =>
                {
                    groupBox2.Text = "Error (" + x + ")";
                }));
            }
            i++;
        }

    }
}).Start();

This code blocks the exception "Cross-thread operation not valid"

Invoke(new Action(() =>
{
    // Form modification code
}));
Sign up to request clarification or add additional context in comments.

2 Comments

You need BeginInvoke() instead of Invoke(). The latter is synchronous and it has the bad habit to deadlock the UI thread.
Correct! Thanks.
1

I think Application.DoEvents(); will let you work with the UI, however this might slow it down a little.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.