2015-03-11 4 views
2

Попытка понять Таймеры и виртуальные клики в C# Winforms. Я хочу, чтобы программа имела введенное значение времени пользователем (textbox1), затем дождалась этого количества времени и щелкнула мышью, а затем увеличила счетчик числа (текстовое поле2).C#, WinForms, ждущие таймеров

В приведенном ниже коде счетчик сразу же переходит в 10, но клики никогда не заканчиваются, несмотря на то, что цикл while установлен для остановки кликов в 10. Я просто хочу, чтобы программа ждала немного случайного времени (время, введенное во время, введенное +3), щелкните мышью, увеличьте счетчик, затем выберите новое случайное число и продолжайте до 10 общих кликов.

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); 
    } 

ответ

2

Проблема заключается в том, что StartClicked обработчик события не блокирует себя. Это простой метод, который без каких-либо циклов задержки в 10 раз меняет переменную уровня метода и изменяет (даже создавая новые!) Свойства таймера.

Возможно сделать то, что вы пытались сделать таким образом (единственный метод с простым циклом), но вам нужно будет использовать обработчик событий async и не потребуется таймер. И как another answer уже обсуждает, как сделать это с классическими таймерами, я дам вам такое асинхронную основе решения:

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; 
    } 
} 

Для получения дополнительной информации по асинхронному ждем вы можете прочитать MSDN on async-await.

+1

Это работает! Я дал вам ответ +, потому что здесь было намного проще, чем в другом варианте (однако, я все равно продолжу и проверю его ответ!) Если вы не возражаете, что означает асинк в целом? Я по-прежнему относительно новичок в программировании, и пока я еще не знаком с этим процессом (у меня нет денег на учебу в школе, поэтому я использую тонны онлайн-курсов и youtubes, поэтому я как бы просто исправляю свои любопытства из других лекций и поисков) , – ShoTo

+1

@ShoTo Да, это намного проще. Целая инфраструктура ожидающего асинхронного ожидания была разработана для упрощения асинхронного программирования (фьючерсы, обратные вызовы, частичное распараллеливание ...). Он также может использоваться таким образом, который позволяет эмулировать таймеры. Но очень важно знать об актуальных таймерах, сходстве потоков, синхронных вызовах синхронизации, конструкциях синхронизации потоков. Это время стоит потратить, знания и опыт, которые значительно улучшат то, как вы видите и понимаете более высокоуровневые вещи, с которыми вы столкнетесь. –

+1

Я не знал, что есть разница. Первоначально я использовал Sleep(), но это было блокирование пользовательского интерфейса, я переключился на таймеры, потому что учебник показал, что он предотвратил блокировку, чего я хотел избежать. Я попытаюсь найти некоторые учебники и базу знаний о потоках и о том, как они работают. Еще раз спасибо! – ShoTo

2

Когда вы говорите _timer.Enabled = true;, остальная часть вашего кода продолжает выполняться. Затем через некоторое время, когда таймер тикает, запускается событие Elapsed.

Кроме того, каждый созданный вами таймер продолжает тикать - они не только срабатывают один раз.

Кроме того, в среде .NET есть много разных классов таймера. Для простого приложения winforms, подобного вашему, я бы придерживался версии System.Windows.Forms.Timer. Вам не нужно беспокоиться о потоках и так далее.

Вы могли бы быть лучше служили чем-то вроде этого:

private Random rsn = new Random(); 
private int numberofclicks = 0; 
private System.Windows.Forms.Timer _timer; 

// set the timer's tick event handler in form_load or similar. 
// you could also just drag a timer onto the form and double-click it. 

private void StartClicked(object sender, EventArgs e) 
{   
    // don't allow starting again until finished 
    btnStart.Enabled = false; 
    numberofclicks = 0; 
    _timer.Interval = /* get randomish interval */ 
    _timer.Start(); 
} 

void _timer_Tick(object sender, EventArgs e) 
{ 
    _timer.Stop(); 
    LeftClick(); 
    numberofclicks++; 
    if (numberofclicks >= 10) { 
     btnStart.Enabled = true; 
    }      
    else { 
     _timer.Interval = /* get randomish interval */ 
     _timer.Start(); 
    } 
} 
+1

Большое вам спасибо! Я получил свой ответ, и я тоже буду экспериментировать с этим методом! Итак, когда я создаю новый _timer, он выбирает (скажем, 3 секунды) время, подсчитывает, запускает событие, сбрасывает, затем подсчитывает вниз, все без остановок? Поэтому я просто создаю 10 таймеров, каждый из которых никогда не останавливается и постоянно щелкает? – ShoTo