2011-06-21 40 views
5

可能重複:
How to block Winforms UI while background thread is running如何鎖定應用程序GUI在C#WinForm的

我使用的是C#WinForm應用程序

我有屏幕,上保存按鈕屏幕的數據被保存到數據庫。

當用戶點擊按鈕應用程序進入數據庫並保存數據時會發生什麼情況。 需要一些時間。

但意思而如果用戶的保存按鈕再次Click事件得到獲取,並在第一次點擊返回到主代碼捕獲事件被解僱(保存數據庫後)..

總之click事件當線程從第一個事件返回 (我嘗試啓用/禁用按鈕的場景)時被捕獲並觸發。

我該如何阻止這種行爲。

問候, AKHIL

@Jalal:我嘗試此代碼與一些修改爲

private readonly object _userActivityLocker = new object(); 
     private void btnSave_Click(object sender, EventArgs e) 
     { 
      if (System.Threading.Monitor.TryEnter(_userActivityLocker)) 
      { 
       //note that any sub clicks will be ignored while we are here 
       try 
       { 
        DateTime dt = DateTime.Now; 
        Thread.Sleep(2000); 
        Debug.Print("FirstClick {0} Second Click {1}",dt.ToLongTimeString(), DateTime.Now.ToLongTimeString()); 
        //here it is safe to call the save and you can disable the btn 
        Application.DoEvents(); 
       } 
       finally 
       { 
        System.Threading.Monitor.Exit(_userActivityLocker); 
        //re-enable the btn if you disable it. 
       } 
      } 
     } 

但是當我快速點擊按鈕(i相5次快速點擊選中)5點擊事件 已被觸發,控制檯窗口正在顯示

FirstClick 1:30:22 PM Second Click 1:30:24 PM FirstClick 1:30 :24 PM Second Click 1:30:26 PM FirstClick 1:30:26 PM Second Click 1:30:28 PM FirstClick 1:30:28 PM Second Click 1:30:30 PM FirstClick 1:30:30 PM Second Click 1:30:32 PM

+0

轉到此鏈接http://stackoverflow.com/questions/648255/how-to-block-winforms-ui-while-background-thread-is-running – Vamsi

+0

奇怪......那麼應該工作 – V4Vendetta

+0

@ V4Vendetta:這是**預期的**發生..看到我的答案更多信息。 –

回答

1

通過啓用,然後重新啓用,因爲你逃避。這有什麼問題?

public void SaveButton_Click(..., ...) 
{ 
    this.SaveButton.Enabled = false; 
    Save(); 
    this.SaveButton.Enabled = true; 
} 
+0

爲防止數據被保存兩次,您還可以添加一個布爾型[dataSaved],將其初始化爲false。 在保存數據之前,您可以檢查布爾變量:如果爲false,則保存,否則顯示警告說數據已保存。 更進一步,只要用戶更新dataset/datatable中的數據,您也可以將flag布爾變量設置爲false,以便用戶能夠再次保存修改後的數據。 –

+0

@Josh Smeaton:我試過啓用/禁用的東西。 – Akhil

+0

@ Moez:是否有其他解決方案..? – Akhil

1

使用System.Threading.Monitor類就可以了,如:

private readonly object _userActivityLocker = new object(); 


private void btnSave_Click(object sender, EventArgs e) 
{ 
    new Thread(delegate() 
    { 
    if (System.Threading.Monitor.TryEnter(_userActivityLocker)) 
    { 
     //note that any sub clicks will be ignored while we are here 
     try 
     { 
      //here it is safe to call the save and you can disable the btn 
     } 
     finally 
     { 
      System.Threading.Monitor.Exit(_userActivityLocker); 
      //re-enable the btn if you disable it. 
     } 
    } 
    }) { IsBackground = true }.Start(); 
} 

爲了證明改變按鈕啓用或禁用狀態不夠這裏一個簡單的測試:

添加新形成並添加一個button1,並在button1內部單擊事件處理程序中寫入以下代碼:

private void button1_Click(object sender, EventArgs e) 
{ 
    button1.Enabled = false; 

    Console.WriteLine("First Message"); 

    Thread.Sleep(2000); 

    Console.WriteLine("second Message"); 

    button1.Enabled = true; 
} 

,然後生成並運行應用程序,雙擊Button1的,結果INT輸出窗口將是:

First Message 
second Message 
First Message 
second Message 

,所以我們必須確保只有點擊執行,即使雙擊左右,並且通過使用System.Threading.Monitor

更新簡單地完成:請注意,您可以使用任務「如果C#4.0」,一個ThreadPool.QueueUserWorkItem或BackgroundWorker的主題作爲一個替代品。

+0

我修改了這個問題,請看看 – Akhil

+0

@kkhil:我忘了將代碼封裝在一個新的Thread中..我的錯。但是我會更新我的答案。 –

+0

@Akhil:編輯後你試過這個嗎?它是否滿足您的需求? –

5

問題在於,當程序將數據保存到數據庫時,程序已經死亡。用戶的鼠標點擊位於消息隊列中,等待您的UI線程恢復生機。當它發生時,該按鈕不再被禁用,因此Click事件觸發。

您可以通過清空消息隊列解決它,點擊處理之前您重新啓用按鈕,在按鈕被禁用:

private void button1_Click(object sender, EventArgs e) { 
     button1.Enabled = false; 
     // Save data to database 
     //... 
     System.Threading.Thread.Sleep(2000); 

     Application.DoEvents(); // Empty the message queue 
     if (!button1.IsDisposed) button1.Enabled = true; 
    } 

不要跳過IsDisposed測試的DoEvents是危險的,因爲它對於處理什麼事件沒有選擇性。它會很高興地讓用戶在你的代碼仍在運行時關閉主窗口。

但更好的解決方案是不要讓你的UI線程死亡這樣。使用BackgroundWorker在工作線程上執行保存。這還可以避免當您的保存需要幾秒鐘時間時Windows放置的醜陋的「不響應」幽靈窗口。它現在可能還沒有這樣做,但是從數據庫成長起的一年之後。您可以重新啓用BGW的RunWorkerCompleted事件處理程序中的按鈕。

+0

@Hans Passant:如果用戶太快地按下按鈕兩次,啓用/禁用將無濟於事,這可能發生在服務器負載過重的情況下... –

+0

嗯,你顯然沒有試過這段代碼。 –

+0

@Hans Passant:不!我確定我測試過了,你現在可以測試你的自我,只需要做以下事情:創建一個新窗體並添加button1到它的click事件處理程序粘貼這個代碼 'button1.Enabled =假; Console.WriteLine(「First Message」); Thread.Sleep(2000); Console.WriteLine(「second Message」); button1.Enabled = true;'當然你必須雙擊按鈕或快速點擊兩次以查看該方法將被調用兩次.....輸出**將是**第一條消息 第二條消息 第一條消息 second message –