3

SQLサーバーでSQLクエリを実行するボタンを持つWPFを構築しています(クエリの実行には時間がかかる場合があります)。そのために TPL を使用したいと考えています。

このコード: var result = Task.Factory.StartNew(() => { command.ExecuteNonQuery(); });

この例外が発生します: ExecuteNonQuery には、オープンで使用可能な接続が必要です。接続の現在の状態は閉じています。

これは、クエリが別のスレッドで実行され、開いている接続を認識していないことが原因だと思います。

質問が 2 つあります。 1. 新しいスレッドにこのオープン接続を知らせるにはどうすればよいですか? 2.これを解決した後、このクエリが原因でウィンドウがフリーズしないようにするにはどうすればよいですか。

ありがとう

4

2 に答える 2

7

タスクの本体内でこのコマンドの接続を作成して開く必要があります。それか、タスクの外部で接続を閉じないでください。これは、ここで行っていることだと思いますが、貼り付けた1行のコードからはわかりません。

私は個人的にそれをすべて Task 本体内で行います。必要がないのに、接続/コマンドのセットアップを取得するまで待つ必要があるのはなぜですか? また、接続が共有インスタンスであり、スレッド間で機能しない可能性もあります。

DB作業をタスクに入れると、デフォルトでスレッドプールスレッドで実行され、WPFディスパッチャースレッドが解放されてUIイベントの処理に戻り、「フリーズ」が防止されます。ほとんどの場合、DB タスクが完了した後に UI を更新する必要があり、そのためには継続タスクを追加するだけですが、その継続タスクから UI を操作できるようにするには、明示的にスケジュールされていることを確認する必要があります。 Dispatcher スレッドで実行します。これは、継続をスケジュールする際に、現在の同期コンテキストの TaskScheduler を明示的に指定することによって行われます。それは次のようになります。

Task backgroundDBTask = Task.Factory.StartNew(() =>
{
    ... DB work here ...
});

backgroundDBTask.ContinueWith((t) =>
{
    ... UI update work here ...
},
TaskScheduler.FromCurrentSynchronizationContext());

ここでの魔法はTaskScheduler::FromCurrentSynchronizationContext、現在の呼び出しの Dispatcher スレッドで実行される継続をスケジュールするメソッドの使用です。

于 2011-05-31T14:35:26.183 に答える
1

@Drew Marshの回答に加えて、

例外を回避するには:

現在の SynchronizationContext は TaskScheduler として使用できない可能性があります

Synchronization Content Exists のチェックを使用できます。

private static TaskScheduler GetSyncronizationContent() => 
     SynchronizationContext.Current != null ? 
          TaskScheduler.FromCurrentSynchronizationContext() : 
          TaskScheduler.Current;

そして代わりにそれを使用してください:

Task backgroundDBTask = Task.Factory.StartNew(() =>
{
    //... DB work here ...
});

backgroundDBTask.ContinueWith((t) =>
{
    //... UI update work here ...
},
GetSyncronizationContent());
于 2016-06-20T11:20:43.333 に答える