2011-12-18 4 views
0

У меня есть WinForm, в котором есть кнопка. В событии нажатия кнопки я вызываю button1.Enabled = false, а затем следуют несколько строк кода. После этого кода я звоню button1.Enabled = true.Странная проблема при отключении кнопки

Это делается, чтобы кнопка не могла быть нажата во время выполнения. Странно то, что, когда кнопка отключена, если пользователь нажимает кнопку много раз, кнопка нажимается.

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

button1.Enabled = false 
//Code 
//Code 
//Code 
button1.Enabled = true 
+0

ли это на самом деле появляется как отключенные после установки Enabled = ложь? – Shai

+0

Возможный дубликат [как заблокировать приложение GUI в C# Winform] (http://stackoverflow.com/questions/6423606/how-to-lock-the-application-gui-in-c-sharp-winform) –

ответ

5

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

(Если это не проблема, пожалуйста, покажите короткую, но полную программу, которая демонстрирует проблему.)

EDIT: Благодаря комментариям Сарвар, я понимаю, почему вы получаете многочисленные события увольняют - они помещаются в очередь (из-за блокировки потока пользовательского интерфейса) и обрабатываются только после повторной активации кнопки. Так что да, если вы избегаете много работы с потоком пользовательского интерфейса, он может обрабатывать клики на отключенной кнопке, игнорировать их, а затем при повторном включении кнопки не будет отставания.

EDIT: Для тех, кто заинтересован в попытке это сами, вот моя тестовая программа демонстрирует эту проблему:

using System; 
using System.Windows.Forms; 
using System.Threading; 
using System.Threading.Tasks; // For the fix below 

class Program 
{ 
    static void Main() 
    { 
     Button button = new Button { Text = "Click me" }; 
     button.Click += HandleClick; 
     Form form = new Form { Controls = { button } }; 
     Application.Run(form); 
    } 

    static void HandleClick(object sender, EventArgs e) 
    { 
     Console.WriteLine("In click handler"); 
     Button button = (Button) sender; 
     button.Enabled = false; 
     Thread.Sleep(10000); 
     button.Enabled = true;   
     Console.WriteLine("Finishing click handler"); 
    } 
} 

И исправление с помощью C# 5 в обращение асинхронной:

static async void HandleClick(object sender, EventArgs e) 
{ 
    Console.WriteLine("In click handler"); 
    Button button = (Button) sender; 
    button.Enabled = false; 
    // Delay by 10 seconds, but without blocking the UI thread 
    await TaskEx.Delay(10000); 
    button.Enabled = true;   
    Console.WriteLine("Finishing click handler"); 
} 
+0

Это это то, о чем я тоже думал, я попробую - спасибо. –

+1

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

+0

@SarwarErfan: Да, это имеет смысл. Редактирование ... –

1

Мы столкнулись с этим такая же проблема и, как сказал Джон, это потому, что пользовательский интерфейс был заблокирован работой, которую мы сделали внутри события click. Когда пользовательский интерфейс возобновился, он зарегистрировал все клики, которые произошли, когда пользовательский интерфейс был заблокирован.

Вот another answer from Stack Overflow, который содержит некоторый код, показывающий, как вы можете исправить эту проблему.

+0

Спасибо за помощь - очень благодарен! –

0

Я решил это с помощью Application.DoEvents(), чтобы освободить очереди перед повторным включением кнопки

AppButton.Enabled = false; 
    ... 
    do some work 
    ... 
    Application.DoEvents(); 
    AppButton.Enable = true; 
Смежные вопросы