События флеш-кликов в C#
Если кнопка запускает длинную задачу, вы, вероятно, не хотите, чтобы пользователь мог снова нажать кнопку (или, возможно, ничего в приложении), пока задача не завершится. Следующий код показывает прямую попытку запретить пользователю щелкнуть кнопку, пока ее код все еще выполняется.
// Подождите 5 секунд. private void btnWaitNow_Click(object sender, EventArgs e) { // Ничто из этого не работает. //this.Enabled = false; //btnWaitNow.Click - = btnWaitNow_Click; btnWaitNow.Enabled = false; this.Cursor = Cursors.WaitCursor; Application.DoEvents(); lstMessages.Items.Add("Wait Now Start " + DateTime.Now.ToString()); Refresh(); System.Threading.Thread.Sleep(5000); lstMessages.Items.Add("Wait Now Stop " + DateTime.Now.ToString()); //this.Enabled = true; //btnWaitNow.Click + = btnWaitNow_Click; btnWaitNow.Enabled = true; this.Cursor = Cursors.Default; }
Когда запускается обработчик событий, он отключает кнопку. Затем он выполняет свою работу и снова включает кнопку.
К сожалению, этот подход не работает. Windows очень успешно ставит в очередь любые ожидающие события мыши, включая клики, когда ваша программа занята, а затем доставляет их, когда обработчик событий заканчивается, чтобы вы могли получить второй клик. (Я мог бы поклясться, что этот подход использовался для работы.)
Один из способов: использовать BackgroundWorker или другую технологию потоков для выполнения работы над отдельным потоком. Отключите кнопку, а затем запустите поток. Когда нить закончится, снова включите кнопку. Этот метод работает и может иметь другие преимущества (например, позволяя пользователю взаимодействовать с другими частями программы, пока задача кнопки все еще работает), но это немного круговое движение.
Другой подход заключается в использовании функции API PeekMessage, как показано в следующем коде.
[StructLayout(LayoutKind.Sequential)] public struct NativeMessage { public IntPtr handle; public uint msg; public IntPtr wParam; public IntPtr lParam; public uint time; public System.Drawing.Point p; } [SuppressUnmanagedCodeSecurity] [return: MarshalAs(UnmanagedType.Bool)] [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool PeekMessage(out NativeMessage message, IntPtr handle, uint filterMin, uint filterMax, uint flags); private const UInt32 WM_MOUSEFIRST = 0x0200; private const UInt32 WM_MOUSELAST = 0x020D; public const int PM_REMOVE = 0x0001; // Сбрасываем все ожидающие события мыши. private void FlushMouseMessages() { NativeMessage msg; // Повторяем до тех пор, пока PeekMessage не вернет false. while (PeekMessage(out msg, IntPtr.Zero, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)) ; }
Этот код содержит кучу деклараций для функции API и ее параметров. (Вам также нужно добавить с помощью операторов для пространств имен System.Runtime.InteropServices и System.Security. Загрузите пример для деталей.) р>
Метод FlushMouseMessages вызывает PeekMessage, чтобы он отклонил любое сообщение в диапазоне WM_MOUSELAST до PM_REMOVE. Код вызывает PeekMessage несколько раз, пока не вернет false, чтобы указать, что таких сообщений нет.
Следующий обработчик событий кнопки вызывает FlushMouseMessage, поэтому вы не можете нажать кнопку, пока код еще не запущен.
// Подождите 5 секунд, а затем сбросьте буфер. private void btnWaitAndFlush_Click(object sender, EventArgs e) { this.Cursor = Cursors.WaitCursor; lstMessages.Items.Add("Wait and Flush Start " + DateTime.Now.ToString()); Refresh(); System.Threading.Thread.Sleep(5000); lstMessages.Items.Add("Wait and Flush Stop " + DateTime.Now.ToString()); FlushMouseMessages(); this.Cursor = Cursors.Default; }