Splash screen a ApplicationContext
Vidět reakci ihned po spuštění programu, je přesně to, po čem touží snad každý uživatel aplikace. Vznikají tak různé splash screeny, které informují uživatele co se právě s aplikací děje. Pro tvůrce aplikace je to něco navíc, co dává ke své aplikaci a přitom by se žádná aplikace neměla bez této úvodní obrazovky objevit. Ano, ano, existují výjimky, ale jestliže aplikace je komplexnější a při startu je potřeba provést náročnější inicializaci, je splash screen nejvhodnějším řešením.
Způsobů jak vytvořit tento úvodní formulář určitě existuje několik, já se chci věnovat jednomu z nich, který považuji za velice elegantní a přímočarý. Určitě však nečekejte, že zde objevíte nádherný formulář, mě zajímalo spíše to, co se skrývá tak říkajíc pod kapotou a jak aplikaci vhodně inicializovat.
Použití ApplicationContext třídy
Jednou z možností jak zahájit zpracování smyčky zpráv je vložení instance třídy ApplicationContext jako parametru do metody Application.Run(). Takto vytvořená instance třídy musí obsahovat odkaz na formulář, který bude sloužit jako context. Při zavření tohoto formuláře poté dojde k ukončení aplikace. To ovšem nemusí platit v okamžiku, kdy je přepsána metoda OnMainFormClosed() a vlastnost MainForm je nahrazena za jinou instanci formuláře, který v ten okamžik převezme context aplikace.
Právě tohoto způsobu můžeme využít k vytvoření splash screenu, inicializaci aplikace a zobrazení hlavního okna aplikace.
Inspirace
Teď určitě někteří mohou namítnout, že takových příkladů je možné najít na internetu dostatek. Což je pravda, ale přesto uvedu své řešení, i z toho důvodu, že jsem na stejné nenarazil a většinou všem takovým příkladům scházelo to hlavní, úvodní inicializace aplikace. Můžete tak najít řešení, která používají timer, vykreslují krásné splash screeny a podobně.
Ač by určitě nebyl problém takovou inicializaci doplnit, jsou zde začátečníci, kterým takovýto návod přijde jistě vhod.
Co budeme potřebovat
Určitě to bude nějaký pěkně vyvedený formulář, který bude sloužit jako splash screen. Jakým způsobem bude takový formulář vypadat nechám na vkusu každého, co však bude zajímavější je jeho jedna případně dvě public metody, které budou aktualizovat stav inicializace a informovat uživatele. Dále to bude formulář hlavní, se kterým bude uživatel aplikace pracovat, ten je v plné režii vývojáře. A v neposlední řadě je to třída, ktérou pojmenujeme třeba SplashApplicationContext a jenž je poděděná od třídy ApplicationContext.
SplashApplicationContext
Tato třída provádí vše co budeme potřebovat k zobrazení splasch screenu a následnému zobrazení hlavního okna aplikace. Zároveň se postará o to, že dojde k potřebné inicializaci aplikace (dynamicky nahrávané moduly, připojení ke vzdálenému serveru a natažení úvodních dat, atd.) a to v samostatném vlákně. Po dokončení inicializace, které může trvat proměnlivě dlouhou dobu, pak dojde k zobrazení hlavního formuláře.
Co je důležité si uvědomit je, že inicializace běží v samostatném vlákně aplikace a tak veškerá volání nad prvky formuláře nebo i formulářem samotným musí být kontrolována a vyvolána z vlákna hlavního (UI).
Třída SplashApplicationContext tak může vypadat následovně:
public class SplashApplicationContext : ApplicationContext{ private FormSplash _splash; private FormMain _main; public SplashApplicationContext () { _splash = new FormSplash(); this.MainForm = _splash; // Thread.CurrentThread.Name = "mainThreadUI"; abychom snáze identifikovali v jakém vlákně se nacházíme Thread thread = new Thread(new ThreadStart(initialize)); // thread.Name = "initializeThread"; thread.Start(); // spustíme inicializaci }}
Po provedení konstruktoru se nastartuje inicializace aplikace v samostatném vlákně, ihned poté dochází k vložení instance contextu do smyčky aplikace - Application.Run(new SplashApplicationContext()) - a zobrazení úvodního formuláře.
V metodě initialize() dochází jednak k inicializaci aplikace a také k aktualizaci stavu, který informuje uživatele o prováděných krocích.
private void initialize() { _splash.PerformStep("Nahrání uživatelského profilu"); // zde je nahrání uživatelského profilu _splash.PerformStep("Nahrání doplňkových modulů"); // nahrajeme nutné doplňkové moduly splashClose();}
Po provedení inicializace, na samém jejím konci dochází k volání zavření formuláře. Proč není volána přímo metoda Close() je bystřejším již jasné, nejsme totiž v hlavním vlákně aplikace a tak bychom se mohli dočkat výjimky. Metoda splashClose(), stejně tak jako metoda PerformStep() tak využívají vlastnosti InvokeRequired a případně vyvolají samu sebe.
private void splashClose() { if (_splash.InvokeRequired) { _splash.Invoke(new MethodInvoker(splashClose)); } else { _splash.Close(); }}
Ještě dříve než skončíme a budeme moci naši skvělou aplikaci spustit a kochat se úvodním formulářem, musíme přepsat metodu OnMainFormClosed().
protected override void OnMainFormClosed(object sender, EventArgs e) { if (sender is FormSplash) { _main = new FormMain(); this.MainForm = _main; this.MainForm.Show(); } else { base.OnMainFormClosed (sender, e); }}
V metodě nejdříve otestujeme, zda dochází k zavření formuláře představujícího náš splash screen, pokud je tomu tak, instancujeme hlavní formulář a přiřadíme ho proměnné MainForm a formulář zobrazíme, tím získá/převezme tento hlavní formulář kontext aplikace. V opačném případě dojde k ukončení aplikace.
Máme hotovo
Tím máme úkol splněn a můžeme aplikaci s dobrým pocitem předat uživatelům, ti pak budou aplikaci vnímat o něco lépe.
3 Comments
pk said
<p>Mam pocit, ze ve tride SplashApplicationContext je chybka, a to sice tyto radky:</p>
<p>private FormSplash = _splash;</p>
<p>private FormMain = _main;</p>
<p>Pokud se jedna o deklaraci promennych (cemuz nasvedcuje jejich inicializace nasledne v konstruktoru), tak by tam pravdepodobne melo byt spis neco jako:</p>
<p>private FormSplash _splash;</p>
<p>private FormMain _main;</p>
<p>Nebo se mylim? Jinak diky, zajimavy pristup, resil jsem to vzdy jinak, znacne kostrbateji.... </p>
<p>Jinak bych se u kodu primlouval alespon za neproporcionalni pismo, kdyz uz neni zvyraznovani syntaxe. Takto je to znacnde necitelne...</p>
said
<p>Jasně, máš pravdu. Hnedka to opravím, ať to někoho nezmate.</p>
<p>Co se týká zváraznění kódu, pokusím se s tím něco udělat, co mi mé znalosti a grafické nadání dovolí. Díky za upozornění.</p>
Velitel said
Jsem začátečník a mě to pořád není jasné.
Napříklád která metoda patří do kterého formuláře mi není z popisu zcela jasné.
Vypadává mi to z kontextu.