2011-05-31 79 views
2

我正在構建一個WPF,它具有在sql server中執行sql查詢的按鈕(查詢可能需要很長時間才能運行)。 我想使用TPL來做到這一點。在使用TPL時避免窗口(WPF)凍結

此代碼: var result = Task.Factory.StartNew(()=> {command.ExecuteNonQuery();});

給出了這個例外: ExecuteNonQuery需要一個開放且可用的Connection。連接的當前狀態已關閉。

我想這是由於查詢在不同的線程上運行並且不知道打開的連接。

我有2個問題: 1.如何讓新線程知道這個打開的連接? 2.解決此問題後,如何讓窗口不因該查詢而凍結。

感謝

回答

6

你必須創建和打開任務的身體內這個命令的連接。或者不要關閉任務外的連接,我認爲這是你在這裏做的,但是不能從你粘貼的一行代碼中分辨出來。

我個人會在任務內部完成所有工作。爲什麼用戶不得不等待你連接/命令設置,如果他們不需要?此外,有可能你的連接是一個共享實例,並且不會跨線程工作。

一旦你將數據庫工作納入任務,它將默認在線程池線程上執行,這將釋放WPF調度程序線程以回到處理UI事件以防止「凍結」。在完成數據庫任務後,很可能需要更新用戶界面,並且爲了能夠從該延續任務操作界面,您需要確保將其顯式調度爲在分派器線程上運行。這是通過在調度延續時顯式指定當前同步上下文的TaskScheduler來完成的。這將是這個樣子:

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

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

這裏的魔法是利用TaskScheduler::FromCurrentSynchronizationContext方法,將安排要在當前通話的調度線程上執行的延續。

+0

感謝,何談第二個問題? – 2011-06-02 06:52:32

+0

增加了更多的細節來回答。 – 2011-06-02 14:32:43

1

除了@Drew沼澤答案,

爲了避免異常:

目前的SynchronizationContext可能不被用作的TaskScheduler

您可以使用檢查同步內容是否存在:

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());