2012-03-08 16 views
5

Mam małą aplikację, która musi przetestować ciągi połączenia SQL dla wielu połączeń (każda wykonywana pojedynczo). Aby to zrobić, tymczasowo ustawiam ConnectionTimeout = 5, aby uniknąć długiego oczekiwania, jeśli połączenie nie jest prawidłowe i, powiedzmy, ConnectionTimeout = 0 (czekać na zawsze).TPL Jak wykonać "oddzwonić"

Aby uniknąć wiszące UI podczas gdy staramy się Open() złe połączenie (nawet z ConnectionTimeout = 5 czekać na SqlException może wynosić do dwudziestu sekund), chcę, aby uruchomić test na osobnym wątku przy użyciu Task Parallel Library (TPL). Więc spin-off mój nowy wątek jak:

Task<bool> asyncTestConn = Task.Factory.StartNew<bool> 
    (() => TestConnection(conn, bShowErrMsg)); 
return asyncTestConn.Result; 

Problemem jest to, że wciąż blokowania UI (wyraźnie), ponieważ czeka na wynik przed powrotem do rozmówcy. W jaki sposób mogę zezwolić, aby kod zwrócił kontrolę do interfejsu użytkownika (zwalniając GUI), jednocześnie uzyskując ostateczny wynik z asynchronicznego Task?

Również z poziomu Task mogę legalnie wykonywać MessageBox.Show("Some message")? To nie działa dla BackgroundWorkers, a ten połączony wątek jest domyślnie wątkiem tła; ale to nie wydaje się być problemem. Dziękuję za Twój czas.

Odpowiedz

4

Masz rację, to jest, gdy czeka się dzieje:

return asyncTestConn.Result; 

Można po prostu zbudować kod mety-up w ogonie TestConnection() lub korzystać z kontynuacją:

// untested 
//Task<bool> asyncTestConn = Task.Factory.Create<bool> (
Task<bool> asyncTestConn = new Task<bool> (
    () => TestConnection(conn, bShowErrMsg)); 
asyncTestConn.ContinueWith(MyFinishCode); 
asyncTestConn.Start() 

Czy mogę zgodnie z prawem wykonać MessageBox.Show("Some message")?

Faktycznie Tak, MessageBox jest bezpieczny dla wątków. Powinno być możliwe także z Bgw.

Ale przedłużasz życie Zadania o wiele, to nie jest dobry pomysł.

+0

Dziękuję bardzo za odpowiedź. Cała idea polega na powrocie do przekazania kontroli do interfejsu użytkownika/GUI tak szybko, jak to możliwe, w jaki sposób/może to osiągnąć? Jeśli wywołuję powyższy kod z metody o nazwie 'ParrTestConn (SqlConnection conn, string bShowErrMsg)', to nie mogę powiedzieć 'asyncTestConn.ContinueWith (ParrTestConn (conn, bShowErrMsg))' ... Czy mogę? – MoonKnight

+0

@Killer Możesz po prostu powrócić po uruchomieniu(). Interfejs GUI powinien być responsywny podczas korzystania z tego. –

+0

Nie mam metody 'Task.Factory.Create ' avilible? – MoonKnight

5

Dla TPL, ContinueWith jest dokładnie tym, czego potrzebujesz. Rozszerzając odpowiedź Henk:

var asyncTestConn = Task.Factory.StartNew(() => TestConnection(conn, bShowErrMsg)); 
// Henk's "MyFinishCode" takes a parameter representing the completed 
// or faulted connection-testing task. 
// Anything that depended on your "return asyncTestConn.Result;" statement 
// needs to move into the callback method. 
asyncTestConn.ContinueWith(task => 
    { 
     switch (task.Status) 
     { 
      // Handle any exceptions to prevent UnobservedTaskException. 
      case TaskStatus.Faulted: /* Error-handling logic */ break; 
      case TaskStatus.RanToCompletion: /* Use task.Result here */ break; 
     } 
    }, 
    // Using this TaskScheduler schedules the callback to run on the UI thread. 
    TaskScheduler.FromCurrentSynchronizationContext()); 
+0

Naprawdę pomocne. Dzięki. Połączenie dwóch odpowiedzi jest absolutnie miętowe. – MoonKnight