2

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";
    }
Alanight
  • 353
  • 2
  • 8
  • 23
FosterZ
  • 3,863
  • 6
  • 38
  • 62
  • 1
    You're going about this the wrong way. All that loop is going to do is take up a huge amount of resources while it constantly loops at full speed. – Harry Oct 13 '10 at 13:45
  • @Harry:hmm, So what you suggest ? – FosterZ Oct 13 '10 at 13:51
  • Read about state machines. Your for loop needs to save its state when it gets paused, and then quit the loop early. Then the resume button needs to start from the saved state. State could be as simple as the value of `i`, or include any number of other local variables. If you wanted to save state across executions of your app, you would need to worry about saving class fields, but for a simple pause/resume those should already be kept intact. – Ben Voigt Oct 13 '10 at 14:47

2 Answers2

4

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;
}
Community
  • 1
  • 1
Dan Tao
  • 125,917
  • 54
  • 300
  • 447
2

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

See here

TalentTuner
  • 17,262
  • 5
  • 38
  • 63
  • my application contineously updates a serverDB fetchin' data from localDB i.e taking data from localDB it updates to serverDB... So i does that in a loop, now i want a option for client to pause,resume or even stop that process. – FosterZ Oct 13 '10 at 13:42