2011-06-21 12 views
5

可能性の重複:
How to block Winforms UI while background thread is runningC#WinフォームアプリケーションのGUIをロックする方法

私は画面どこに保存]ボタンを持っているのC#のWinFormアプリケーション

を使用しています画面のデータはデータベースに保存されます。

ユーザーがボタンをクリックすると、アプリケーションはデータベースに行き、データを保存します。 時間がかかります。短いクリックイベントで

が、ユーザが再びClickイベントがキャッチイベントがクビcatchedと(データベースを保存した後)、メインコードの最初のクリックしてリターンを取得[保存]ボタンをクリックするとしながら、意味..

スレッドが最初のイベント (私はボタンの有効/無効のシナリオを試してみました)から戻るときに捕捉され、解雇されます。

この動作を停止するにはどうすればよいですか。

よろしく、 アクヒル

@Jalal:5クリック(私は5回急速クリックで確認)私は

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. 
       } 
      } 
     } 

として、いくつかの変更でこのコードを試してみましたが、私は急速ボタンをクリックしたときイベント が実行され、コンソールウィンドウが表示されます

FirstClick 1:30:22 PM第2クリック1:30:24 PM FirstClick 1:30 :24 PM第2クリック1:30:26 PM FirstClick 1:30:26 PM第2クリック1:30:28 PM FirstClick 1:30:28 PM第2クリック1:30:30 PM FirstClick 1:30:30 PM第2クリック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

有効にしてから、もう一度やり直してください。これの問題は何でしたか?

System.Threading.Monitorクラスはトリックのように行います使用して
public void SaveButton_Click(..., ...) 
{ 
    this.SaveButton.Enabled = false; 
    Save(); 
    this.SaveButton.Enabled = true; 
} 
+0

データが2回保存されないようにするには、Boolean [dataSaved]を追加して、falseに初期化します。 データを保存する前に、Boolean変数をチェックします。falseの場合は保存し、そうでない場合は、データがすでに保存されているという警告を表示します。 さらに、ユーザーが変更されたデータを再度保存できるように、ユーザーがデータセット/データテーブルのデータを更新するたびに、フラグboolean変数をfalseに設定することもできます。 –

+0

@Josh Smeaton:私は有効/無効のものを試しました。 – Akhil

+0

@ Moez:他の解決策は何ですか? – Akhil

1

:状態を有効または無効にするには、ボタンを変更すると、ここで簡単なテストだけでは不十分であることを証明するために

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をclickイベントハンドラ内に追加するには、次のコードを記述します。

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; 
} 

して、ビルドして実行するアプリケーションを、ダブルクリックをボタン1にし、出力ウィンドウINT結果は次のようになります。

First Message 
second Message 
First Message 
second Message 

ので、私たちは確信してクリックするだけの場合でもダブルクリックするか、そうとその実行されていることを確認する必要がありますスレッドの代替としての「C#4.0ならば、」あなたは、タスクを使用することができます注意、ThreadPool.QueueUserWorkItemまたはBackgroundWorkerの:System.Threading.Monitor

Updateを使用して簡単に達成。

+0

質問を修正しました。 – Akhil

+0

@kkhil:私は新しいスレッドでコードをラップすることを忘れています。しかし、私は私の答えを更新します。 –

+0

@Akhil:編集後にこれを試しましたか?それはあなたのニーズに合っていますか? –

5

問題は、データがデータベースに保存されている間、プログラムが世界中で死んでいることです。ユーザーのマウスクリックがメッセージキューに置かれ、UIスレッドが復帰するのを待っています。クリックすると、ボタンは無効にならなくなり、Clickイベントが発生します。

あなたは、ボタンを再度有効にする前に、ボタンが無効になっている間にクリックが処理されるように、メッセージキューを空にすることによってそれを解決することができます、IsDisposedテストをスキップしないでください

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; 
    } 

をDoEvents関数もあるため危険ですどのイベントが処理されるかについて選択的ではありません。あなたのコードがまだ動いている間、喜んでメインウィンドウを閉じることができます。

しかし、よりよい解決策は、あなたのUIスレッドがこのように死んでしまわないようにすることです。 BackgroundWorkerを使用して、ワーカースレッドで保存を実行します。これにより、保存に2〜3秒以上かかる場合にWindowsが表示する醜い "Not Responding"ゴーストウィンドウも回避されます。おそらくこれはまだまだ行われていませんが、dbaseが成長してから1年後です。 BGWのRunWorkerCompletedイベントハンドラのボタンを再び有効にすることができます。

+0

@Hans Passant:ユーザーがボタンを2回押しすぎると、有効/無効には役立たないでしょう。サーバーが負荷をかけているときに発生する可能性があります。 –

+0

うん、あなたは明らかにこのコードを試しませんでした。 –

+0

@Hans Passant:いいえ!確かにテストしましたが、あなたは今自分でテストすることができます。新しいフォームを作成してbutton1を追加し、そのクリックイベントハンドラでこのコードを貼り付けてください 'button1.Enabled =偽; Console.WriteLine( "First Message"); Thread.Sleep(2000); Console.WriteLine( "second Message"); button1.Enabled = true; 'もちろん、ボタンをダブルクリックするか、すぐに2回クリックすると、メソッドが2回呼び出されます。.....出力** **最初のメッセージ 2番目のメッセージ 最初のメッセージ 2番目のメッセージ –

関連する問題