locked
How do I test a button when running an event? RRS feed

  • Question

  • I have a start button which runs a section of code continuously - how do I test the stop button while this code is running?
    Wednesday, May 24, 2006 7:58 PM

Answers

  • Colin,
    it is usually not a good idea to have an event executing for a long time, as while you are serving an event, the other events get blocked. This amounts to freeze the user interface.

    If you plan to have a lengthy task running in response to a button click, you should probably use a Thread, or the ThreadPool. It's fairly easy to use, and it's well worth the little time it takes to set them up, as the code becomes cleaner and easier to manage.

    Anyway, there is another option, and it is to call Application.DoEvents (), that will allow other events to be raised and served. The obvious drawback is that you might reenter the same event, and this might lead to unexpected results. What follows is a silly example of how you may go using DoEvents ():

    private bool stop = false;
    private void Button1_Click (...) {
      stop = false;
      for (int i = 0; (! stop) && (i < 1000); i++) {
        // do something time consuming here... for instance:
        Thread.Sleep (100);
        Application.DoEvents ();
      }
      if (stop)
        MessageBox.Show ("Stopped");
      else
        MessageBox.Show ("Done");
    }

    private void Button2_Click (...) {
      stop = true;
    }

    HTH
    --mc

    Wednesday, May 24, 2006 9:10 PM
  • Colin,
    you are totally right: the example I gave you does require two clicks... weird.

    My original code was written for two toolstrip buttons, and those will have no problem. The buttons instead will require the two clicks you were talking about. The reason seems to be that the button control keeps the mouse captured through all the execution of the event. The extra click is needed to "convince" the first button to release the capture and is therefore lost as a click.

    As I mentioned before, not all controls behave this way.

    You can release the capture from Button1, changing the code to:

    private void Button1_Click (...) {
      stop = false;
      Button1.Capture = false;
      for (...

    Moving the focus away would also work, but it would be inconsistent with the standard Windows behaviour.

    Hope this helps
    --mc

    Thursday, May 25, 2006 1:09 PM
  •  Mario Cossi wrote:

    private void Button1_Click (...) {
      stop = false;
      Button1.Capture = false;
      for (...

    Mario.......That is now a complete solution - Thank you very much.

     

    Thursday, May 25, 2006 1:30 PM

All replies

  • Colin,
    it is usually not a good idea to have an event executing for a long time, as while you are serving an event, the other events get blocked. This amounts to freeze the user interface.

    If you plan to have a lengthy task running in response to a button click, you should probably use a Thread, or the ThreadPool. It's fairly easy to use, and it's well worth the little time it takes to set them up, as the code becomes cleaner and easier to manage.

    Anyway, there is another option, and it is to call Application.DoEvents (), that will allow other events to be raised and served. The obvious drawback is that you might reenter the same event, and this might lead to unexpected results. What follows is a silly example of how you may go using DoEvents ():

    private bool stop = false;
    private void Button1_Click (...) {
      stop = false;
      for (int i = 0; (! stop) && (i < 1000); i++) {
        // do something time consuming here... for instance:
        Thread.Sleep (100);
        Application.DoEvents ();
      }
      if (stop)
        MessageBox.Show ("Stopped");
      else
        MessageBox.Show ("Done");
    }

    private void Button2_Click (...) {
      stop = true;
    }

    HTH
    --mc

    Wednesday, May 24, 2006 9:10 PM
  • The other way I would suggest is using Threading.

    Create a global thread variable.
    And in your void, create a threadstart that address of the procedures / functions.
    Add this threadstart to this thread variable and do a start.

    In other button, assigned an abort or interrupt action to stop the thread.

     

    Thursday, May 25, 2006 1:39 AM
  •  Mario Cossi wrote:

     there is another option, and it is to call Application.DoEvents (), 

    Thanks Mario, that works fine - but I find I need to double click on the button - a single click does nothing - is this normal or have I upset some other parameter?

     

    Thursday, May 25, 2006 11:05 AM
  • Well, a single click must work. If you have to click multiple times to get your button behave, then you might not be calling DoEvents often enough. Try to split the lengthy process in parts and call DoEvents after each part.

    HTH
    --mc 

    Thursday, May 25, 2006 11:11 AM
  •  Mario Cossi wrote:

    Well, a single click must work.

    Thanks for you reply Mario - I have typed in the exact example as you have given it except the sleep statement which I have typed as follows:-

    System.Threading.Thread.Sleep(10);

    I need two clicks of button2 to stop the loop. It can be two quick clicks or two clicks a few seconds apart but it definitely need two clicks. I am running C# Express. Are you sure it should operate with one click?

    Thursday, May 25, 2006 12:37 PM
  • best practices for continous code is using threads like most people say in here :)

    Not so smart to use a continous loop inside a program. Altho there are few ways to make continous code.

    1. Threads <<< U should really try it, its easy and fun to work with.

    2. Maybe try adding a event handler to Application.Idle event

     

    In case u know a little c++ u will know there is allready a mainloop in each application, checking for messages (like the window paint message, button click messages)

    .NET translates this all for u in events and stuff ... but still, when there is no message received the application is idle, so u can attach an event handler to the application.idle event ;)

     

    This way your code will been executed continously ... but event like button click events will be processed before your code is called.

    Thursday, May 25, 2006 12:47 PM
  •  Nightmare_BE wrote:

    best practices for continous code is using threads

    1. Threads <<< U should really try it, its easy and fun to work with.

    2. Maybe try adding a event handler to Application.Idle event

    Thanks for the reply. This is my first few days of programming in Windows (Visual C#) - I have written complex programmes in C and assembler but always at DOS level. Can you give me a complete example using a thread to operate a continuous loop started with a button click and using a different button to stop the loop.

    Thanks.

    Thursday, May 25, 2006 1:00 PM
  • Colin,
    you are totally right: the example I gave you does require two clicks... weird.

    My original code was written for two toolstrip buttons, and those will have no problem. The buttons instead will require the two clicks you were talking about. The reason seems to be that the button control keeps the mouse captured through all the execution of the event. The extra click is needed to "convince" the first button to release the capture and is therefore lost as a click.

    As I mentioned before, not all controls behave this way.

    You can release the capture from Button1, changing the code to:

    private void Button1_Click (...) {
      stop = false;
      Button1.Capture = false;
      for (...

    Moving the focus away would also work, but it would be inconsistent with the standard Windows behaviour.

    Hope this helps
    --mc

    Thursday, May 25, 2006 1:09 PM
  •  Mario Cossi wrote:

    private void Button1_Click (...) {
      stop = false;
      Button1.Capture = false;
      for (...

    Mario.......That is now a complete solution - Thank you very much.

     

    Thursday, May 25, 2006 1:30 PM
  • Here some sample code for using threads.

    I added 2 button event handlers to stop the thread loop

    First one will end the loop by using a variable to stop it

    Second one will abort the thread directly

     

     

    U dont need to use the thread.join method ... Lets say u start the thread using a button in a form ... no need for the join, cause the application will keep running.

    In case u start the thread in your void Main() ... u should use it. cause else after u start the thread, the application will end (end of void main reached) and your thread will be aborted

     

    [code]

    using System;

    using System.Collections.Generic;

    using System.Text;

    // Add the threading namespace

    using System.Threading;

    namespace ComboBoxValues

    {

    public class ThreadSample

    {

    // Thread handle

    Thread myThread = null;

    // Exit flag

    private bool m_exit = false;

    public void StartThread()

    {

    // Reset the exit flag

    m_exit = false;

    // Create the thread

    myThread = new Thread(new ThreadStart(myThread));

    // Start the thread

    myThread.Start();

    // Wait for the thread to end

    myThread.Join();

    }

    public void MyThread()

    {

    // Loop until the exit flag is set to trough

    while (!m_exit)

    {

    // Continous loop code

    // Save some cpu usage

    Thread.Sleep(10);

    }

    }

    public void Button1_Click(object sender, EventArgs e)

    {

    // Set the exit flag to true

    // Code will process till end of the loop, then will abort

    // Thread will be ended successful

    m_exit = true;

    }

    public void Button2_Click(object sender, EventArgs e)

    {

    // Abort the thread

    // Code will be aborted even when not end of loop is reached

    // Thread will be ended non successful (ThreadAbortException)

    myThread.Abort();

    }

    }

    }

    [/code]

    Friday, May 26, 2006 7:44 AM