2012-12-05 15 views
5

Piszę klasę, która wykonuje pewną operację w bibliotece. Ale operacja jest nużąca i chcę być w stanie dowiedzieć się o postępie metody wewnątrz tej klasy, dzięki czemu mogę jej używać w aplikacji WinForms do raportowania postępu.Pisanie metody zgłaszania postępu

Mam zamiar uruchomić moją klasę w innym wątku w mojej aplikacji WinForm i chcę, aby klasa została oddzielona od obaw aplikacji WinForm i nie chcę jej wiązać z niczym innym niż to robi.

Jaki byłby najlepszy sposób wdrożenia mechanizmu raportowania postępu w klasie biblioteki?

Czy byłoby dobrze mieć zmienną postępu w klasie i dodać do niej odbiornik zdarzeń w mojej aplikacji WinForm? A jeśli tak, jak mogę to zrobić?

Edit: mam przed używane klasę BackgroundWorker, ale moim problemem jest to, że nie chcę, aby moje klasy biblioteki, aby zajmować się którykolwiek z wielowątkowości operacji. Tak więc nie chcę wywoływać klasy biblioteki w klasie ReportProgress, chcę (może) mieć zmienną w klasie, która zawiera bieżący postęp i chcę, aby wątek interfejsu użytkownika w jakiś sposób "zasubskrybował" go. Nie wiem, czy to dobry sposób na zaprojektowanie tego.

+0

Jest wiele różnych podejść do tego, ale jak wygląda twój istniejący kod ...? pomogłoby ci, gdybyś dostarczył tego, co dotychczas próbowałeś. – MethodMan

+0

Nie mam w tej chwili zbyt wiele kodu. Chciałem dowiedzieć się, jak postępować najpierw przed napisaniem lekcji. Byłbym bardzo wdzięczny, gdybyś mógł wskazać mi jakieś znane podejście do tego problemu. – hattenn

Odpowiedz

4

Sprawdź klasę BackgroundWorker. Obsługuje automatyczne tworzenie wątków między wątkami w celu raportowania postępów i ma bardzo prosty model zdarzeń dla tego rodzaju wsparcia.

Edit: Biorąc pod uwagę swoją pozycję na użyciu BackgroundWorker bezpośrednio, co można zrobić, to stworzyć prosty wrapper:

// Error checking elided for expository purposes. 
public interface IProgressReporter 
{ 
    void ReportProgress(int progress, object status); 
} 

public class BackgroundWorkerProgressReporter : IProgressReporter 
{ 
    private BackgroundWorker _worker; 
    public BackgroundWorkerProgressReporter(BackgroundWorker worker) 
    { 
     _worker = worker; 
    } 

    public void ReportProgress(int progress, object status) 
    { 
     _worker.ReportProgress(progress, status); 
    } 
} 

Następnie zmieniać konstruktora (lub dodać obiekt) klasy, które chcesz aby zgłosić postęp, aby zaakceptować IProgressReporter. Jest to forma zastrzyku zależności i powinna znacząco umożliwić Twojemu obiektowi zgłaszanie postępów, a jednocześnie unikanie określonych zależności od bibliotek wątków.

+0

Sprawdź moją edycję. – hattenn

+0

Dodałem przykład kodu, którego można użyć. – Rob

1

Tutaj można zrobić 2 różne sposoby będę po poniższych obie opcje, które pomogą skierować Cię w dobrym kierunku

Ty powinny robić to w innym wątku, a następnie aktualizację wątku UI z tego wątku. Blokujesz dalsze przetwarzanie, wykonując tę ​​pracę w wątku interfejsu użytkownika.

Jeśli nie przenieść ten kod do wątku UI, to zawsze można zadzwonić Application.DoEvents, ale zdecydowanie Proponuję zbadać te opcje najpierw:

drugi alternatywny mógłby zrobić coś takiego:

trzeba uzyskać dane z jednego wątku do drugiego. Można to zrobić na kilka sposobów ...

Po pierwsze, twój wątek "tła" może aktualizować pewnego rodzaju zmienną łańcuchową "CurrentStatus", która zmienia się wraz z upływem czasu. Następnie możesz umieścić zegar na formularzu, który następnie pobierze zmienną CurrentStatus i zaktualizuje ją etykietą.

Po drugie, można po prostu wywołać operację z wątku tła do wątku interfejsu użytkownika z delegatem za pomocą właściwości InvokeRequired formantu etykiety. Tak na przykład ...

private delegate void UpdateStatusDelegate(string status); 
private void UpdateStatus(string status) 
{ 
    if (this.label1.InvokeRequired) 
    { 
     this.Invoke(new UpdateStatusDelegate(this.UpdateStatus), new object[] { status }); 
     return; 
    } 

    this.label1.Text = status; 
} 

można nazwać UpdateStatus() metoda z dowolnego wątku (UI lub tła) i to wykryje, czy nie musi powoływać się na działanie w głównym wątku UI (a jeśli więc to robi).

Edit: Aby właściwie ustawić wątek, można to zrobić tak:

private void StartProcessing() 
    { 
     System.Threading.Thread procThread = new System.Threading.Thread(this.Process); 

     procThread.Start(); 
    } 

    private void Process() // this is the actual method of the thread 
    { 
     foreach (System.IO.FileInfo f in dir.GetFiles("*.txt")) 
     { 
      // Do processing 
      // Show progress bar 
      // Update Label on Form, "f.Name is done processing, now processing..." 
      UpdateStatus("Processing " + f.Name + "...");     
     } 
    } 

wtedy, gdy użytkownik kliknie przycisk „Go” będzie po prostu zadzwonić StartProcessing().

+0

Proszę sprawdź moją edycję. – hattenn