Při vývoji aplikací typu WinForms používáme okna, popisky, vstupní textová pole, tlačítka atd. Celá aplikace je řízena událostmi. Například kliknutím na tlačítko dojde k události, která změní text nějakého popisku.
Pokud obsluha nějaké události (např. obsluha kliknutí na tlačítko DownloadDataButton) trvá moc dlouho (data se stahují z internetu, je to třeba soubor o velikosti několika set MB), uživateli se může zdát, že aplikace "zamrzla". Aplikace totiž nereaguje na jeho kliknutí apod., protože pomalá metoda události pro stažení dat ještě nedoběhla.
Abychom se vyhnuli pocitu uživatele, že GUI aplikace přestalo reagovat, je možné spustit časově náročný výpočet (stahování velkého objemu dat) ve vedlejším vlákně, tzv. background thread, neboli vlákně běžícím na pozadí. Hlavní vlákno, které obsluhuje události, se tak "nezasekne" v dlouho běžícím handleru a uživatel je spokojený: aplikace reaguje na jeho akce s myší nebo klávesnicí.
Problém nastane, když chce vedleší vlákno dát uživateli vědět, že se něco stalo. Např. chceme zobrazit info: Do stažení celého souboru zbývají 2 minuty a 45 sekund. A tuto informaci chceme pravidelně aktualizovat, aby měl uživatel přehled, za jak dlouho zhruba bude soubor kompletně stažený.
Oknová appka napsaná v .NET-u běží v operačním systému Windows v tzv. Single Thread Apartment neboli STA, což znamená, že se předpokládá, že s oknovými ovládacími prvky (tlačítka, textová pole apod.) interaguje pouze jediné (tzv. hlavní, někdy též foreground thread) vlákno aplikace. Pokud by se např. o zapsání textu do labelu nebo text boxu pokusilo jiné vlákno, mohlo by dojít k porušení datové integrity aplikace a jejímu nepředvídatelnému chování.
Aby mohl programátor použít v režímu STA více vláken a zároveň aby nedocházelo k výše popsaným chybám, nabízí .NET třídu BackgroundWorker. Tato třída umožňuje bezpečné předávání dat mezi hlavním vláknem (běžícím na popředí) a vedlejšími vlákny (běžícími na pozadí) tak, aby bylo informace od vedlejších vláken možné zobrazit třeba na nějakém formulářovém panelu nebo v text boxu.
Tři nejdůležitější události, které třída BackgroundWorker nabízí, jsou tyto:
Událost | V jakém kontextu běží | K čemu je |
---|---|---|
DoWork | Na pozadí (background thread) | Veškerý kód pomalu běžící operace, která by jinak zdržovala odpovědi na akce uživatele v GUI (kliknutí myší) |
ProgressChanged | Na popředí (foreground thread) | Zobrazení progresu operace, která běží na pozadí (např. kolik procent celé operace již bylo dokončeno) |
RunWorkerCompleted | Na popředí | Zobrazení výsledku operace, která běžela na pozadí (např. "Operace přerušena uživatelem", "Vyskytla se chyba", nebo "OK, hotovo!") |
Vedlejší vlákno, které poběží na pozadí a bude vykonávat kód "pomalé" operace, se aktivuje voláním
metody RunWorkerAsync na objektu BackgroundWorker
.
Celý průběh dlouho trvající operace může vypadat např. takto:
Dokumentace na Microsoftu: https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.backgroundworker
Ukázka použití objektu BackgroundWorker ke stažení.
Dokumentace na Microsoftu: https://docs.microsoft.com/en-us/dotnet/api/system.threading.semaphore