2013-12-20 4 views
3

У меня есть приложение со многими пользовательскими элементами управления и несколькими кнопками на каждом, каждая кнопка имеет событие OnClick, которое делает некоторые важные вещи, а затем отправляет новый пользовательский элемент управления.C# windows forms handle click spam

Проблема возникает, когда пользователь нажимает очень быстро несколько раз, код события запускается несколько раз, прежде чем выходить на новый пользовательский элемент управления, вызывая проблемы.

Мое текущее решение состоит в том, чтобы отключить кнопку в самой первой строке обработчика событий, но делать это с каждым окном и обработчиком было бы хлопотно, что я могу сделать?

EDIT: Будет ли это хорошим решением для вывода из Button и переопределить событие OnClick, поэтому он всегда проверяет «рабочую» переменную, и если это правда, она не запускает событие? Что-то вроде:

public class MyButton : Button 
{ 
private static bool isWorking = false; 

protected override void OnClick(EventArgs e) 
{ 
    if (!isWorking) 
    { 
     isWorking = true; 
     base.OnClick(e); 
     isWorking = false; 
    } 
    //Else do nothing 
} 

}

ответ

1

Если вы хотите, чтобы все кнопки ждать, пока работа одной кнопки не будет сделана, добавьте bool isProcessing переменные в форму. Заверните работу каждой кнопки внутри if (!isProcessing) и установите для этого флага значение true в первой строке внутри оператора if. Затем не забудьте установить его обратно в false перед тем, как выйти из if.

Я предполагаю, что вы делаете все это асинхронно, поскольку, если все это в одном потоке, форма будет блокироваться, пока она обрабатывает работу. Тем не менее, это решит вашу проблему.

+0

То же, что и выше, мне пришлось бы реплицировать один и тот же код (if! IsProcessing, set true/false) для каждого обработчика событий, я хочу этого избежать. – user1777914

+0

К сожалению, нет простого решения для того, чтобы все обработчики событий могли что-то сделать, не кодируя их все. – krillgar

1

Отключение элементов управления при работе с конфиденциальной информацией является типичным решением, которое я всегда применяю.

Но поскольку на одном экране может быть достаточно нескольких элементов управления, на которые влияет некоторый щелчок или изменение пользовательского интерфейса, я обычно разрабатываю формы, чтобы иметь специализированный метод, который проходит через все затронутые элементы управления и соответственно отключает/разрешает их.

Что-то вроде этого:

void EnableControls(bool enable) 
{ 
    foreach (Control ctl in this.Controls) 
     ctl.Enabled = enable; 
} 

Кроме того, вы могли бы сгруппировать элементы управления в связанные ведра, так, чтобы отключить/включить только один из них и т.д. В зависимости от ваших точных потребностей.

Существует альтернативное решение для использования таймера - отключите кнопку, но включите ее через 1 секунду. Это предотвращает нажатие нескольких пользователей, если это может привести к повреждению данных (т. Е. Каждый клик рассматривается как новая операция).

+0

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

+0

Все дело в том, что вы не копируете код нигде. Если вы можете найти общую логику, то вы можете настроить обработчики один раз для всех элементов управления - просто пропустите все их и подпишитесь на событие Click каждой кнопки с тем же обработчиком. Этот обработчик вызывает включение/отключение таким же образом для всех кнопок в форме. –

+0

Theres что-то я думаю, что вы меня не поняли, проблема не в том, что у меня много кнопок, но у многих пользовательских элементов управления (каждый имитирует другое окно), где у каждого есть 1 или 2 кнопки, которые делают чувствительную работу. – user1777914

1

Я бы назвал ту же функцию от каждой кнопки, а затем выполнить определенную задачу:

private void Button_Click(object sender, EventAgrs e) 
{ 
    Button btn = sender; 
    btn.disable = true; 
    switch (btn.AccessibleName) 
    // call specific function for the particular button or do it all here 
} 
+0

Это интересный подход, но я должен был бы написать каждый обработчик событий, и я не думаю, что это будет возможно. – user1777914

3

Вы можете использовать некоторые timeStamp для задержки между 2 клика:

DateTime timeStamp; 
//this will handle the clicks with the allowed interval being 0.5 second 
//Note that a tick is equal to 1/10,000,000 of second. 
private void click_Handler(object sender, EventArgs e) { 
    if ((DateTime.Now - timeStamp).Ticks < 5000000) return; 
    timeStamp = DateTime.Now; 
    //your code goes here .... 
} 
+0

То же, что и выше, мне пришлось бы реплицировать этот код на каждом обработчике событий – user1777914

+0

@ user1777914 не быть таким ленивым, есть только один способ, которым вам не нужно добавлять обработчик для какого-либо события для вашего управления, - это создать пользовательский контроль, обрабатывать все внутри. Я сомневаюсь, что вы даже не знаете, что обработчик может обрабатывать многие события **, это означает, что в этом случае 'click_Handler' может обрабатывать все события' Click' ваших кнопок. Вам просто нужно проверить «отправителя», чтобы увидеть, какая кнопка нажата, поэтому ** Почему вы думаете, что здесь есть дублированный код **? –

+0

Было бы здорово, если бы я мог добавить атрибут Action Filter (как и ASP.NET MVC) к моим обработчикам, поэтому я мог бы выполнять код до и после. Но C# не поддерживает декораторов и перехватчиков =/ – user1777914

0

Я не уверен, если это будет даже работать, а просто идея ...

Вы можете попробовать с аспектно-ориентированным подходом (например, с помощью Postsharp):

  1. Создайте два аспекта: один для ввода метода и один для выхода метода. В методе ввода отметьте текущий метод как «обработка» (например, добавьте имя метода в хэш-набор).В методе exit отметьте метод как «не обрабатывать» (удалите его из набора хэшей). Затем в записи метода проверьте, обрабатывается ли метод и если он есть, затем отмените метод (например: https://stackoverflow.com/a/2437794/113858)
  2. Отметьте все обработчики событий с этим аспектом.
+0

Да, использование аспектно-ориентированного подхода было бы хорошим, я не знаю, почему это не поддерживается C# изначально, с ASP.NET MVC у вас есть фильтры действий, которые могут сделать почти то, что вы описанное выше, это должно быть возможно без какой-либо внешней библиотеки. – user1777914