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

當我第一次按下按鈕時。它禁用。然後開始doSomeThing()。但是當我再次按下按鈕時,doSomeThing()事件在此按鈕啓用後會再次觸發。WPF中的禁用按鈕觸發事件

那麼,如何防止按鈕被禁用時觸發事件?

+0

按鈕實際上是否在點擊時更改爲禁用的視覺效果?如果沒有,你的問題可能類似於[這個問題](http://stackoverflow.com/questions/9519295/updatelayout-on-wpf-click/9519860#9519860) – ianschol 2012-03-02 03:10:08

+0

是的,它改變視覺外觀以禁用 – HelloWorld 2012-03-02 03:12:33

回答

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

它看起來像事件在按鈕啓用後觸發。所以,但是.IsEnabled將始終爲真 – HelloWorld 2012-03-02 03:27:40

+0

你在doSomething()方法中做了什麼? – 2012-03-02 04:06:10

+0

它正在做Thread.Sleep(50)和一些計算的大部分時間 – HelloWorld 2012-03-02 04:11:23

3

似乎有些澄清是爲了...

  • 控制(e.g.-按鈕)正確地禁用。
  • 只要主線程正在處理原始的單擊事件,後續事件就不會被處理 - 而是會被排隊。
  • 只要第一次點擊事件完成,就會處理下一個排隊的事件。
  • 此時,由於控件已啓用,排隊的單擊事件將再次觸發事件處理程序。

有幾種可能的解決方案,我認爲@Amit在正確的軌道上 - 使用線程可能是最好的方法。

這裏是爲我工作的簡化版本:

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 
} 

對於一個很好的解釋爲什麼不用Application.DoEvents()look here

對於控件的狀態線程安全的操作,請參見: 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; 

}