FosterZ
FosterZ

Reputation: 3911

Pause and Resume a For-Loop in C#

I'm working on a windows App in C#, I have a for-loop which update something in a loop, and I have 3 buttons on the form named "Stop,Pause,Resume". So the purpose is as same as the buttons named. Does anyone know how to do this?

Here is the Loop

    private void btnCompleteAuto_Click(object sender, EventArgs e)
    {
        setGeneralValue();
        for (int i = 1; i <= autoGridView.Rows.Count - 1; i++)
        {
            if (SRP == "Pause") // this is what I was thinking but it won't work
            {                   // it will step into end-less loop
              do                // how to stop this loop on "Resume" button click
              {

              }while(SRP!="Resume")

            }
            car = false;
            try
            {
                MemberID = Convert.ToInt64(autoGridView.Rows[0].Cells["Member_ID"].Value);
                DispID = Convert.ToString(autoGridView.Rows[0].Cells["Disp_Id"].Value);
                Mobile = Convert.ToString(autoGridView.Rows[0].Cells["Mobile"].Value);
                DueDate = Convert.ToString(autoGridView.Rows[0].Cells["Due_Date"].Value);

            }
            catch (Exception)
            {
                MessageBox.Show("Row Not Found");
            }

            AutoRecharge(network_name, pack_name, Mobile, Mobile, Convert.ToString(autoGridView.Rows[0].Cells["Rck_Amt"].Value), vendor_id, vendor_pwd, pack_id, oxinetwork_id);
            autoGridView.Rows.RemoveAt(0);
        }
    }

Here are the 3 button events in which I'm setting a variable

    private void btnPause_Click(object sender, EventArgs e)
    {
        SRP = "Pause";
    }

    private void btnStop_Click(object sender, EventArgs e)
    {
        SRP = "Stop";
        autoGridView.DataSource = "";
    }

    private void btnResume_Click(object sender, EventArgs e)
    {
        SRP = "Resume";
    }

Upvotes: 2

Views: 11506

Answers (2)

Dan Tao
Dan Tao

Reputation: 128317

The reason this doesn't work as you expect is this:

A Windows Forms application uses a single UI thread, which continually processes incoming messages from a queue. Any event handlers you attach to the events of a Windows Forms control get sent to this queue and processed by the UI thread as quickly as possible.

Your btnCompleteAuto_Click is one such handler. Once it starts, nothing else will be processed by the UI thread until it exits. Thus any other handlers you attach to other events (btnPause_Click, btnStop_Click, etc.) must wait their turn, as they will run on the same (UI) thread.

If you want pause/resume functionality, this has to be achieved on a separate thread.

A possible way to implement it might be to use a BackgroundWorker, as suggested by saurabh.

Here is a rough sketch of what your updated code might look like (I have not even attempted to compile this, let alone debug it; it's intended only as a basic outline of how you might accomplish this functionality).

You need to be aware, however, that accessing UI controls directly from a non-UI thread is a no-no. Use a mechanism such as the BackgroundWorker.ProgressChanged event to handle any UI updates that you need to happen based on activity on a non-UI thread.

ManualResetEvent _busy = new ManualResetEvent(false);

private void btnCompleteAuto_Click(object sender, EventArgs e)
{
    if (!backgroundWorker.IsBusy)
    {
        _busy.Set();
        btnAutoCompleteAuto.Text = "Pause";
        backgroundWorker.RunWorkerAsync();
    }
    else
    {
        _busy.Reset();
        btnAutoCompleteAuto.Text = "Resume";
    }

    btnStop.Enabled = true;
}

private void btnStop_Click(object sender, EventArgs e)
{
    _busy.Set();
    backgroundWorker.CancelAsync();
}

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    // for (something)
    // {

        _busy.WaitOne();

        if (backgroundWorker.CancellationPending)
        {
            return;
        }

        // Do your work here.

    // }
}

private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    _busy.Reset();
    btnAutoCompleteAuto.Text = "Start";
    btnStop.Enabled = false;
}

Upvotes: 4

TalentTuner
TalentTuner

Reputation: 17556

After Reading your actual requirement in our comment , i would suggest that use Background worker class which supports cancellation of running process.

See here

Upvotes: 2

Related Questions