BackgroundWorker.ReportProgress

0

Witam

wrzuciłem backgroundworker + progressbar do swojego programu, wszystko działa ok, z tym, że chciałbym przenieść zawartość metody, o której wykonywaniu się informuje progressbar do osobnej metody w specjalnie wydzielonej klasie. I tu pojawia się problem. Jak wtedy informować backgroundworkera o postępie w wykonywaniu się metody, kiedy nie mamy dostępu do licznika pętli, który ukryty jest jak już wcześniej napisałem w metodzie innej klasy? Z góry dziękuję za wszelkie sugestie :)

Bardziej obrazowo:

  private void bWsynchro_DoWork(object sender, DoWorkEventArgs e)
        { 
          Obliczenia.mojaMetoda(); 
         }
0

Chodzi ci o ProgressChanged?
Albo niech Obliczenia.mojaMetoda() po prostu zwraca skok na progressbar'ze(wtedy użyjesz tego jako BW.ReportProgress(Obliczenia.mojaMetoda())). Albo możesz w tej klasie utworzyć metodę o sygnaturze takiej jak ProgressChangedEventHandler i podpiąć ją pod ProgressChanged twojego BW. Dodatkowo przekazać tej klasie referencję do progressbara, którym ma poruszać, lub zrobić to samo za pomocą delegatów.

0

Delegaty dobry pomysł, referencja do progressbara w klasie średni - nie powinno się wiązać logiki obliczeniowej z GUI tak silnie.

0

Kod klasy formatki, na której umieszczony jest progressBar:

 
    public partial class Synchro : Form
    {
        Downloader dwn;  
        int progress;
        public Synchro()
        {
            InitializeComponent();
            dwn = new Downloader();
            bWsynchro.DoWork += new DoWorkEventHandler(bWsynchro_DoWork);
            bWsynchro.ProgressChanged += new ProgressChangedEventHandler(bWsynchro_ProgressChanged);
            bWsynchro.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bWsynchro_RunWorkerCompleted);
        }
        private void bWsynchro_DoWork(object sender, DoWorkEventArgs e)
        {
            bWsynchro = sender as BackgroundWorker;
            if ((bWsynchro.CancellationPending == true)) 
            {
                e.Cancel = true;
            }
            else 
            {
                dwn.Obliczenia(); 
                bWsynchro.CancelAsync(); 
            }
        }
        private void bWsynchro_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progress = e.ProgressPercentage;
        }
        public void pUpdate(int i)
        {
            Console.WriteLine(i);
        } 
        private void bWsynchro_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        { }
        private void bStart_Click(object sender, EventArgs e)
        {
            if (bWsynchro.IsBusy != true)
            {
                bWsynchro.RunWorkerAsync();   
            }
        }
    }

Kod klasy odpowiadającej za żmudne obliczenia:

 
    class Downloader
    {
        public static int progress;
        public void Obliczenia()
        {
            Synchro s = new Synchro(); 
            try
            {
                        for (int i = 0; i < k; i++)
                        {
                            progress = Convert.ToInt32(Math.Round(licznik * 100.0 / n, 2));
                            s.pUpdate(progress); 
                        }
            }
            catch (SoapException soapex)
            { }
        } 
    }
1

Po pierwsze:

  Synchro s = new Synchro();

</quote> Tworzysz NOWY OBIEKT klasy synchro (twojej formy z progressbarem)

 s.pUpdate(progress); 

</quote> Robisz update na NOWYM OBIEKCIE klasy synchro, TO NIE ZMIENI niczego na twojej formie glownej.

Po drugie: chyba nie zrozumiałeś do końca istoty działania BW.
Moja rada jest taka: daruj sobie BW w formie, skoro chcesz żeby cała operacja była wykonywana w klasie Downloader, to tam utwórz sobie BW. Definicja DoWork bedzie w klasie Downloader, a w klasie Synchro ustawisz tylko ProgressChanged i RunWorkerCompleted tegoż BW. Dzięki temu Downloader będzie wykonywał swoją operację, w międzyczasie raportował progres do formy głównej(bez brutalnego dłubania w jej zmiennych), a po zakończeniu operacji zaraportuje koniec pracy.

Nie wiem czy to pominąłeś w umieszczonym tu kodzie, czy nie masz tego u siebie, ale musisz ustawić jeszcze dwie flagi na true: WorkerSupportsCancellation(żeby można było anulować BW) i WorkerReportsProgress(żeby można było raportować postęp) bez tego dostaniesz wyjątkami po oczach ;) Dodatkowo używając tego

if ((bWsynchro.CancellationPending == true))
{
e.Cancel = true;
}

w tym miejscu gdzie użyłeś nic ci nie da. Sprawdzanie tej flagi powinieneś wstawić w miejsce tej pętli:

for (int i = 0; i < k; i++)
{
//Tu sprawdzasz czy w miedzyczasie nie zostalo anulowane - jeżeli tak to daj return, żeby wyszło z DoWorka, 
//ustawienie jedynie Cancel = true tak naprawdę nic ci nie da 
progress = Convert.ToInt32(Math.Round(licznik * 100.0 / n, 2));
//Tu update 
} 
0
adams85 napisał(a)

Moja rada jest taka: daruj sobie BW w formie, skoro chcesz żeby cała operacja była wykonywana w klasie Downloader, to tam utwórz sobie BW. Definicja DoWork bedzie w klasie Downloader, a w klasie Synchro ustawisz tylko ProgressChanged i RunWorkerCompleted tegoż BW. Dzięki temu Downloader będzie wykonywał swoją operację, w międzyczasie raportował progres do formy głównej(bez brutalnego dłubania w jej zmiennych), a po zakończeniu operacji zaraportuje koniec pracy.

Działa! O takie szybkie i proste rozwiązanie właśnie mi chodziło, wielkie dzięki adams85! :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1