Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Do stuff while button pressed down? [solved]

Do stuff while button pressed down? [solved]

Scheduled Pinned Locked Moved C#
helpquestion
5 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Offline
    L Offline
    la01
    wrote on last edited by
    #1

    Hello CPers, I'm trying to get a Winform to do some stuff while a button is pressed down, and stop doing it when the button's let go. I'm trying this out in a simple form with a button and a label. So as long as the button is pressed (MouseDown) the value displayed on the label should keep incrementing by 1. I've tried to used a BackgroundWorker for this and have so far failed. So, in my form class I have:

    BackgroundWorker bwAsync = new BackgroundWorker();

    public Form1() {
    InitializeComponent();

    bwAsync.WorkerReportsProgress = true;
    bwAsync.WorkerSupportsCancellation = true;
    bwAsync.DoWork += new DoWorkEventHandler(bwAsync\_DoWork);
    

    }

    private void button1_MouseDown(object sender, MouseEventArgs e) {

    bwAsync.RunWorkerAsync();
    

    }

    private void button1_MouseUp(object sender, MouseEventArgs e) {

    bwAsync.CancelAsync();
    

    }

    void bwAsync_DoWork(object sender, DoWorkEventArgs e) {

    BackgroundWorker bwAsync = sender as BackgroundWorker;
    
    int i;
    label1.Invoke( (MethodInvoker)delegate()
    {
        i = int.TryParse(label1.Text, out i) ? i : 0;
        while(!bwAsync.CancellationPending){
            Console.WriteLine("down");
            label1.Text = i.ToString();
            i++;
        }
    });
    

    }

    What happens here is, once it goes into DoWork() it gets stuck in the loop, and it never gets to the MouseUp handler. Anyone have any feeback on my code, or on how it's supposed to be done? Would be much appreciated. Thank you.

    modified on Sunday, June 13, 2010 11:47 PM

    L 1 Reply Last reply
    0
    • L la01

      Hello CPers, I'm trying to get a Winform to do some stuff while a button is pressed down, and stop doing it when the button's let go. I'm trying this out in a simple form with a button and a label. So as long as the button is pressed (MouseDown) the value displayed on the label should keep incrementing by 1. I've tried to used a BackgroundWorker for this and have so far failed. So, in my form class I have:

      BackgroundWorker bwAsync = new BackgroundWorker();

      public Form1() {
      InitializeComponent();

      bwAsync.WorkerReportsProgress = true;
      bwAsync.WorkerSupportsCancellation = true;
      bwAsync.DoWork += new DoWorkEventHandler(bwAsync\_DoWork);
      

      }

      private void button1_MouseDown(object sender, MouseEventArgs e) {

      bwAsync.RunWorkerAsync();
      

      }

      private void button1_MouseUp(object sender, MouseEventArgs e) {

      bwAsync.CancelAsync();
      

      }

      void bwAsync_DoWork(object sender, DoWorkEventArgs e) {

      BackgroundWorker bwAsync = sender as BackgroundWorker;
      
      int i;
      label1.Invoke( (MethodInvoker)delegate()
      {
          i = int.TryParse(label1.Text, out i) ? i : 0;
          while(!bwAsync.CancellationPending){
              Console.WriteLine("down");
              label1.Text = i.ToString();
              i++;
          }
      });
      

      }

      What happens here is, once it goes into DoWork() it gets stuck in the loop, and it never gets to the MouseUp handler. Anyone have any feeback on my code, or on how it's supposed to be done? Would be much appreciated. Thank you.

      modified on Sunday, June 13, 2010 11:47 PM

      L Offline
      L Offline
      Luc Pattyn
      wrote on last edited by
      #2

      Hi, your label1.Invoke causes the entire while loop to execute on the main thread (so it is allowed to touch the Label), however that also blocks the thread, so your button1_MouseUp handler cannot react to the button being released. (The main thread processes its event queue, popping and executing one message at a time). Furthermore, your while loop does not contain any timing control (such as a Thread.Sleep), so it will spin as fast as it can (depending on the characteristics and the load of your system), and clogging your Console. I would use a very different approach, without BGW: - have a class member of type System.Windows.Forms.Timer; - have a class member "int tickCount"; - in button1_MouseDown clear tickCount and launch that timer, with an appropriate interval (say 100 msec), and a tick handler basically containing:

      Console.WriteLine("down");
      tickCount++;
      label1.Text=tickCount.ToString();

      - in button1_MouseUp simply stop the timer. The advantages would be: code is much simpler, everything runs on the main thread, which is idle most of the time, as all it does is run one tick handler every 100 msec. :)

      Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


      Nil Volentibus Arduum


      L 1 Reply Last reply
      0
      • L Luc Pattyn

        Hi, your label1.Invoke causes the entire while loop to execute on the main thread (so it is allowed to touch the Label), however that also blocks the thread, so your button1_MouseUp handler cannot react to the button being released. (The main thread processes its event queue, popping and executing one message at a time). Furthermore, your while loop does not contain any timing control (such as a Thread.Sleep), so it will spin as fast as it can (depending on the characteristics and the load of your system), and clogging your Console. I would use a very different approach, without BGW: - have a class member of type System.Windows.Forms.Timer; - have a class member "int tickCount"; - in button1_MouseDown clear tickCount and launch that timer, with an appropriate interval (say 100 msec), and a tick handler basically containing:

        Console.WriteLine("down");
        tickCount++;
        label1.Text=tickCount.ToString();

        - in button1_MouseUp simply stop the timer. The advantages would be: code is much simpler, everything runs on the main thread, which is idle most of the time, as all it does is run one tick handler every 100 msec. :)

        Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


        Nil Volentibus Arduum


        L Offline
        L Offline
        la01
        wrote on last edited by
        #3

        THAT was ridiculously easy and clean. To think I spent the better part of the day trying to manipulate threads.. :doh: Thanks, Luc!

        L 1 Reply Last reply
        0
        • L la01

          THAT was ridiculously easy and clean. To think I spent the better part of the day trying to manipulate threads.. :doh: Thanks, Luc!

          L Offline
          L Offline
          Luc Pattyn
          wrote on last edited by
          #4

          No problem. Yes one tends to find convoluted ways first. BTW: You may want to switch to a BGW as soon as some real work needs to be done. Then the calculations would go into the DoWork handler (without Invoke!) and hence really run on the BGW thread, however reporting progress or intermediate results to the GUI would best be handled by calling ReportProgress(), which causes the ProgressChanged handler to run on the main thread automatically. :)

          Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


          Nil Volentibus Arduum


          L 1 Reply Last reply
          0
          • L Luc Pattyn

            No problem. Yes one tends to find convoluted ways first. BTW: You may want to switch to a BGW as soon as some real work needs to be done. Then the calculations would go into the DoWork handler (without Invoke!) and hence really run on the BGW thread, however reporting progress or intermediate results to the GUI would best be handled by calling ReportProgress(), which causes the ProgressChanged handler to run on the main thread automatically. :)

            Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


            Nil Volentibus Arduum


            L Offline
            L Offline
            la01
            wrote on last edited by
            #5

            Your suggestions are much appreciated. Will do :)

            1 Reply Last reply
            0
            Reply
            • Reply as topic
            Log in to reply
            • Oldest to Newest
            • Newest to Oldest
            • Most Votes


            • Login

            • Don't have an account? Register

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • World
            • Users
            • Groups