Search code examples
c#while-loopmouseeventsystem.timers.timer

C#, WinForms, waiting for timers


Trying to understand Timers and virtual clicks in C# Winforms. I want to have the program have an entered time value by the user (textbox1), then wait that amount of time and click the mouse, then increase the number counter (textbox2).

In the code below, the number counter immediately goes to 10, but the clicks are never ending, despite having a while loop set to stop the clicks at 10. I basically just want the program to wait a slightly random time (time entered to time entered +3), click the mouse, increase the counter, then pick a new random number and continue until 10 total clicks.

 public Form1()
    {
        InitializeComponent();
    }

    private void NumbersOnly(object sender, KeyPressEventArgs e)
    {
        char ch = e.KeyChar;
        if (!Char.IsDigit(ch) && ch != 8)
        {
            e.Handled = true;
        }
    }

    static System.Timers.Timer _timer;
    int numberofclicks = 0;
    [DllImport("user32.dll")]
    static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);
    private const int MOUSEEVENTF_MOVE = 0x0001;
    private const int MOUSEEVENTF_LEFTDOWN = 0x0002;
    private const int MOUSEEVENTF_LEFTUP = 0x0004;
    private const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
    private const int MOUSEEVENTF_RIGHTUP = 0x0010;
    private const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
    private const int MOUSEEVENTF_MIDDLEUP = 0x0040;
    private const int MOUSEEVENTF_ABSOLUTE = 0x8000;


    private void StartClicked(object sender, EventArgs e)
    {
        numberofclicks = 0;
        Random rsn = new Random();

        while (numberofclicks < 10)
        {
            string startseconds = textBox1.Text;
            int timerstartseconds = Convert.ToInt32(startseconds);
            int timertime = rsn.Next(timerstartseconds * 1000, ((timerstartseconds + 3) * 1000));
            _timer = new System.Timers.Timer(timertime);

            _timer.Elapsed += _timer_Elapsed;
            _timer.Enabled = true;

            textBox2.Clear();
            numberofclicks++;
            string numbertextbox = numberofclicks.ToString();
            textBox2.Text = numbertextbox;

        }
    }

    void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        LeftClick();                        
    }

    public static void LeftClick()
    {
        mouse_event(MOUSEEVENTF_LEFTDOWN, Control.MousePosition.X, Control.MousePosition.Y, 0, 0);
        mouse_event(MOUSEEVENTF_LEFTUP, Control.MousePosition.X, Control.MousePosition.Y, 0, 0);
    }

Solution

  • The problem lies in a fact that StartClicked event handler does not block itself. It is just a simple method that without any delay loops 10 times changing the method level variable and modifying(even creating new!) Timer properties.

    It is possible to do what you attempted to do in such a manner(single method with simple loop), but you will have to use async event handler and will have no need for a timer. And as the another answer already discusses how to do it with classic timers, I will give you such async-based solution:

    private async void StartClicked(object sender, EventArgs e)
    {
        numberofclicks = 0;
        Random rsn = new Random();
    
        while (numberofclicks < 10)
        {
            string startseconds = textBox1.Text;
            int timerstartseconds = Convert.ToInt32(startseconds);
            int timertime = rsn.Next(timerstartseconds * 1000, ((timerstartseconds + 3) * 1000));
    
            await Task.Delay(timertime);
            LeftClick();
    
            textBox2.Clear();
            numberofclicks++;
            string numbertextbox = numberofclicks.ToString();
            textBox2.Text = numbertextbox;
        }
    }
    

    For more information on async-await you can read MSDN on async-await.