2012-03-02 22 views
3
private void but_Click(object sender, RoutedEventArgs e) 
{ 
    (sender as Button).IsEnabled = false; 
    doSomeThing(); 
    (sender as Button).IsEnabled = true; 
} 

初めてボタンを押すと、それは無効になります。次にdoSomeThing()を起動しますが、ボタンをもう一度押すとdoSomeThing()but_Clickイベントが再び発生します。無効ButtonはWPFのイベントを発生させます

ボタンを無効にしている間に発射イベントを防止するにはどうすればよいですか?

+0

ボタンをクリックすると、実際にボタンが無効な視覚的な外観に変わりますか?そうでない場合は、あなたの質問はおそらく[この質問](http://stackoverflow.com/questions/9519295/updatelayout-on-wpf-click/9519860#9519860)と似ています – ianschol

+0

はい、視覚的な外観を無効に変更します – HelloWorld

答えて

1

このコードの問題は、doSomeThing()メソッドがUIスレッドで実行されていることです。したがって、ボタンは正しく無効になっていません。 doSomeThing()メソッドが別のスレッドで実行されるようにコードをリファクタリングすると、正常に動作します。以下は、BackgroundWorkerを使用した簡単な例です。しかし、私たちはUIスレッドで時間のかかるものを実行すべきではないという考えです。ここで、リファクタリング、コードは次のとおりです。

public partial class ButtonEnableTest : Window 
{ 
    private BackgroundWorker worker = new BackgroundWorker(); 

    public ButtonEnableTest() 
    { 
     InitializeComponent(); 
     this.worker.DoWork += new DoWorkEventHandler(worker_DoWork); 
     this.worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); 
    } 

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if (this.btn.IsEnabled == false) 
     { 
      this.btn.IsEnabled = true; 
     } 
    } 

    void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     doSomeThing(); 
    } 

    private void doSomeThing() 
    { 
     int i = 5; 
     while (i > 0) 
     { 
      Thread.Sleep(TimeSpan.FromMilliseconds(2000)); 
      System.Diagnostics.Debug.WriteLine("Woke up " + i); 
      i--; 
     } 
    } 

    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     Button btn = (Button) sender; 
     System.Diagnostics.Debug.WriteLine("at ButtonClick"); 
     if (btn.IsEnabled) 
     { 
      btn.IsEnabled = false; 
      this.worker.RunWorkerAsync(); 
     } 
    } 
} 

私はちょうど私の考えを共有したいと思って、私はここで任意のコード変換に従っていませんでした。私はWPFボタンを "btn"と命名しました。

0
private void but_Click(object sender, RoutedEventArgs e) 
{ 
    Button but = (sender as Button) 
    if(but.IsEnabled) 
    { 
     but.IsEnabled = false; 
     doSomeThing(); 
     but.IsEnabled = true; 
    } 
} 
+0

ボタンが有効になった後にイベントが発生します。だから、but.IsEnabledは常にtrueになる – HelloWorld

+0

doSomething()メソッドで何をしていますか? –

+0

Thread.Sleep(50)といくつかの計算のほとんどの時間 – HelloWorld

3

いくつかの明確化がために...

  • コントロール(e.g.-ボタン)が適切に無効化されているようです。
  • メインスレッドが元のクリックイベントを処理している限り、後続のイベントは処理されず、キューに入れられます。
  • 最初のクリックイベントが完了すると、次のキューに入れられたイベントが処理されます。
  • この時点では、コントロールが既に有効になっているため、キューに入れられたクリックイベントによってイベントハンドラが再びトリガされます。

可能な解決策がいくつかあります。@Amitが適切な道筋にあると思います。スレッドを使用するのがおそらく最善の方法です。

ここでは私のために働い何の簡易版だ:参照、コントロールの状態のスレッドセーフな操作のためのApplication.DoEvents()look here

を使用しない理由は良い説明のために

private void Button1_Click(object sender, EventArgs e) 
{ 
    disableControls(); // e.g.- Button1.Enabled = false; 

    // run "doSomething" in a separate thread 
    new Thread(new ThreadStart(doSomething)).Start(); 
} 

private void doSomething() 
{ 
    // do something... make sure it's thread-safe!! 
    // ... 

    enableControls(); // a thread safe enabling of relevant controls 
} 

How to: Make Thread-Safe Calls to Windows Forms Controls

0

TextChangedイベントで同様の問題が発生し、そのコードで解決しました。

private void TB_box_TextChanged(object sender, TextChangedEventArgs e) 
{ 
    //detach event 
    TB_box1.TextChanged -= TB_box_TextChanged; 
    TB_box2.TextChanged -= TB_box_TextChanged; 

    //change my value 
    TB_box1.Text = "a" 
    TB_box2.Text = "b" 

    //attach event  
    TB_box1.TextChanged += TB_box_TextChanged; 
    TB_box2.TextChanged += TB_box_TextChanged; 

} 
関連する問題