2009-08-01 7 views
18

Mam Windows Forms aplikacji na które muszę użyć pętli for posiadające dużą liczbę zdalnych połączeń około 2000 - 3000 połączeń,winform aplikacji UI zawiesza się podczas długotrwałych Operation

i podczas wykonywania przez Pętla, tracę kontrolę nad formami i formami kontrolnymi, ponieważ staje się to dużym procesem i po pewnym czasie pokazuje "Nie odpowiada", ale jeśli długo czekam, to wróci, myślę, że muszę użyć do tego celu jakiegoś modelu wątków , czy jest jakiś pomysł, jak mogę przystąpić do rozwiązania problemu?

+0

Umieść 'Application.DoEvents()' w pętli. – i486

Odpowiedz

43

Musisz wykonać długą operację na wątku tła.

Istnieje kilka sposobów na zrobienie tego.

  1. Można kolejce wywołanie metody w celu wykonania na wątku puli wątków (Patrz here):

    ThreadPool.QueueUserWorkItem(new WaitCallback(YourMethod)); 
    

    W .NET 4.0 można użyć TaskFactory:

    Task.Factory.StartNew(() => YourMethod()); 
    

    I w .NET 4.5 i nowszych można (i należy, a nie TaskFactory.StartNew()) używać Task.Run():

    Task.Run(() => YourMethod()); 
    
  2. Możesz użyć BackgroundWorker, aby uzyskać większą kontrolę nad metodą, jeśli potrzebujesz rzeczy takich jak aktualizacje postępu lub powiadomienia po zakończeniu. Przeciągnij formant BackgroundWorker na formularz i dołącz swoją metodę do zdarzenia dowodu. Następnie po prostu uruchom pracownika, gdy chcesz uruchomić swoją metodę. Możesz oczywiście utworzyć BackgroundWorker ręcznie z kodu, pamiętaj tylko, że musi on zostać usunięty po zakończeniu.

  3. Stwórz zupełnie nowy wątek, aby Twoja praca mogła się odbyć. Jest to najbardziej skomplikowane i nie jest konieczne, chyba że potrzebujesz naprawdę drobiazgowej kontroli nad wątkiem. Zobacz stronę MSDN na klasie Thread, jeśli chcesz się o tym dowiedzieć.

Pamiętaj, że z niczego gwintowane, ty nie może Aktualizacja GUI lub zmiany jakichkolwiek formantów GUI z wątku tła. Jeśli chcesz zrobić cokolwiek na GUI, musisz użyć Invoke (i InvokeRequired), aby uruchomić metodę z powrotem na wątku GUI. Zobacz here.

+1

Myślę, że to mi pomoże, spróbuję BackGroundWorker! – shahjapan

+0

'BackgroundWorker' wydawało się, że to dla mnie dobra sztuczka! –

2

Bez wątku. Użyj Application.DoEvents(); //repaint or respond to msg Na przykład:

foreach (DirectoryInfo subDir in dirInfo.EnumerateDirectories()) 
{ 
    count = count + 1; 
    listBoxControl4.Items.Add(count.ToString() + ":" + subDir.FullName); 
    Application.DoEvents(); //allow repaint to see status 
    ProduceListing(subDir, " "); 
} 

To będzie przejść przez wszystkich folderów rekurencyjnie i napisać nazwiska na liście. Może to zająć dużo czasu. Przy pomocy DoEvents(), pokaże postęp w każdej pętli. Zasadniczo, wywołanie pozwala oknom w tym wątku aktualizować wszystko w pętli msg systemu Windows. Pamiętaj, aby uważać na niezamierzoną rekursję, ponieważ jakakolwiek kontrola w formularzu zostanie ponownie kliknięta, nawet jeśli twoja pierwsza nie została jeszcze zakończona. To działa dobrze. (Jest to kopia starej aplikacji Delphi Application.ProcessMessages(). Możesz ją wyszukać, aby sprawdzić, dlaczego działa i na co zwrócić uwagę.

+4

Wywołanie "DoEvents" jest złe. Może powodować wszelkiego rodzaju problemy z wątkami, takie jak ponowne entrancy. Należy go całkowicie unikać. – Enigmativity

+0

-1 Dokładnie to, czego szukałem. Ale z zupełnie przeciwnego powodu. Chcę uruchomić coś w tle i wstrzymać interfejs w pętli, więc następna rzecz nie nastąpi, dopóki ten pracownik tła nie zakończy pracy. Wykonanie zdarzenia BackgroundWorker's pozwala ustawić wartość logiczną. Interfejs użytkownika działa podczas (! [This boolean]) {Application.DoEvents(); Sen (50);}. – TamusJRoyce

+0

+1 Uwielbiam używać Application.DoEvents() do prostych aplikacji, które buduję dla siebie, szybciej koduję. Zauważyłem, że można z niego korzystać, o ile wiesz, że przetwarza wszystkie zdarzenia, które mogą przerwać twoją pętlę, takie jak zamknięcie formularza. Zazwyczaj wyłączam przycisk po kliknięciu i wyłączam zamykanie formularza w trakcie jego działania. – Aximili

4
private voidForm_Load(object sender, EventArgs e) 
    { 
     MethodInvoker mk = delegate 
     { 
      //your job 
     }; 
     mk.BeginInvoke(callbackfunction, null); 
    } 

    private void callbackfunction(IAsyncResult res) 
    { 
     // it will be called when your job finishes. 
    } 

użyć MethodInvoker to najprostszy sposób.

Powiązane problemy