Jarda Jirava

Vývojář a architekt řešení postavených na technologii .net framework. Zabývám se jak vývojem webových aplikací za pomoci asp.net, tak také desktopových aplikací winform. Při návrhu řešení a samotném vývoji pak využívám dlouholetých zkušeností se zpracováním obchodní logiky a pravidel aplikací získaných z vývoje komerčních aplikací pro finanční a bankovní instituce.

Microsoft MVP

Microsoft MVP - Client App dev

Silverlight minesweeper

Get Microsoft Silverlight

Navrhi COOL design a vyhraj zkušební let po Evropě!

Poslední příspěvky

6
IV

Chyby, testování a daně

Původně jsem si říkal, že takový příspěvek snad není ani nutné psát. Každý přece ví, že do konce března mají být zaplaceny daně - samozřejmě zde platí výjimky. A tak se rozpoutal nelítostný souboj portálů zaměřených na ekonomiku a finance o to, kdo nabídne lépe propracované prostředí k výpočtu daní.

Jelikož je i mojí povinností podávat daňové přiznání, využil jsem tohoto konkurečního boje a stáhl si nabízené formuláře pro výpočet daně. Nechci tím naznačit, že bych nevěřil všemožným online kalkulačkám, které se objevily. Avšak mít možnost si rovnou vytisknout potřebné formuláře a donést je ke správci příslušné daně bylo pro mě lákavější.

Využil jsem souboru, ve kterém bylo nejen daňové přiznání, ale zároveň také formuláře pro správu sociálního zabezpečení a zdravotního pojištění.

A právě v tuto chvíli se dostávám k tomu, proč je tento příspěvek zaměřen na chyby a testování - a hlavně daně. Ač jsou jistě všechny připravované soubory zpracovávány schopnými účetními firmamy, jedno jim schází. To, co pokládá každý vývojář v současné době za nutnost a to je testování a odhalování chyb. Teď se nemusíte čehokoli obávat, pokud nepatříte do stejné minoritní skupiny jako já, určitě jste daňové přiznání podali správně.

Právě však na testování krajních mezí, nebo chcete-li krajních hodnot "dojel" můj výpočet daně. Což není, jak sami jistě uznáte, vůbec potěšující zjištění - obzvláště, když mi vyšlo, že bych měl zaplatit více, než skutečně musím. Přestože jsou v zákoně tyto krajní meze již několik let, tyto kalkulačky s nimi nepracují. Přitom jak jsem následně zjistil, jejich implementace není nemožná a ani složitá - pro jistotu jsem si to ověřil u mého správce daně, který provedl kontrolu.

Je tedy na pováženou, zda tyto kalkulačky někdo testuje, nebo zda portály důvěřují svým dodavatelům. Jak se zdá, ne vždy se to může vyplatit a ztráta důvěry v tomto ohledu není příjemná. Ba co více, tyto kalkulačky pocházejí od účetních firem, kde se do nich jistě vyplňuje několik daňových přiznání, kolik tak může být postižených jedinců a je možné takovým firmám potom důvěřovat?

Testováním by tak měl projít každý software, byť se na první pohled zdá, že se jedná jen o několik málo vzorečků, na kterých není co zkazit.

Publikováno pod: krátké postřehy
4
III

WPF Photo organizer I

WPF aplikace jistě začnou v dohledné době okupovat naše PC miláčky. Několik takových aplikací se již pomalu začíná objevovat, jedná se jak o čtečky novinových článků, tak i ostatní neméně zajímavé aplikace. Ostatně, ty zajímavé můžete nalézt v přehledu na channel 9.

Co však u takové aplikace, uvedené ve zmíněném přehledu chybí, je popis jak ji vytvořit. Ano, takový jednoduchý, srozumitelný návod, pro nás vývojáře, kteří se chceme zabývat vývojem aplikací pro WPF, tedy tvorbou UI v jazyce XAML. Někdo jistě může namítnout, že příkladů na netu existuje dostatek, ale přiznám se, že popsaný vývoj jedné aplikace jsem nikde nenašel, vždy se jednalo jenom o samostatné části, vytvoření nebo nastylování Buttonu, případně seriál o WPF jako takovém, třeba jako ten na vývojáři. Jelikož je WPF zajímvavá technologie, pustil jsem se do tvorby jednoduchého organizátoru fotografií. Jelikož jsem si říkal, že pro vývojáře není důležitý jen výsledný efekt, ale i postup, jak se k cíly dostat, rozhodl jsem se s Vámi podělit a v několika příspěvcích tak představit tvorbu takové aplikace.

Cíl mého snažení

Samozřejmě, že je možné stáhnout si nejrůznější organizátory fotografií, tak proč jsem se rozhodl zrovna pro aplikaci takového typu? Jedním z kriterií bylo, že pro takovou aplikaci není třeba příliš programování ve vrstvě aplikační a také databázové logiky. Zato je možné představit nejrůznější možnosti, které nabízí WPF, takže většina kódu může být deklarována za pomoci XAML. Na druhou stranu jsem nechtěl, aby byla aplikace přeplácána různými efekty, jako je reflexe apod. to u mě určitě nenajdete.

Jako jedno z vylepšení, které se příliš u podobných aplikací nevidí a které si myslím využiji, je možnost označit fotografii k tisku a uvedení počtu kopií. Jistě to znáte, chcete si některé své digitální fotografie nechat vytisknout a tápete, jak si je označit a poznamenat k nim, v kolika kopiích je chcete mít (obzvláště důležité v současné chvíli, kdy nechávám tisknout fotky Davídka ;-) ).

Co všechno aplikace umí

Pojďme se tedy podívat na to, jakou funkčností jsem tento organizátor fotografií vybavil.

Import fotografií
  • k importu fotografií do aplikace dojde pomocí výběru adresáře na disku
  • zároveň s tím, se daný import pojmenuje a tak vznikne sada obrázků
Informace k fotografii

v průběhu importu se z fotografie zjišťují některé základní informace a EXIF informace jako:

název, datum pořízení, iso, clona, čas, model fotoaparátu ...

Fotografii je možné označit popiskem a také ji přiřadit tagy.

Základní pohledy
  • pohled na fotografie podle složky importu - vzniklé sady
  • pohled na fotografie podle jejich doby pořízení - zajištěno pomocí stromového menu
  • pohled na fotografie podle definovaných tagů - tagy je možné přiřazovat obrázkům během importu, tak i v průběhu prohlížení
  • pohled na jednotlivou fotografii dle výběru
  • tzv. paper tray pohled, kdy se zobrazují pouze fotografie k tisku

Aplikace během importu vytváří malé náhledy na obrázky a tyto ukládá do aplikačního adresáře. Zároveň jsou veškeré zjištěné informace k fotografii ukládány do databáze. Pro tyto účely jsem zvolil databázi SQL Server Compact edition, která by měla svým výkonem dostačovat pro všechny případy a zároveň je velice jednoduchá na instalaci.

Je důležité se zmínit o tom, že se zdrojovou fotografií se nemanipuluje. Fotografie vložené do paper tray je možné vyexportovat pro úpravy, tak aby nebyla dotčena původní fotografie.

Doufám, že jsem Vás naladil a nalákal na pokračování, které již nebude jen o teorii. Zároveň, pokud máte nějakou připomínku nebo dotaz, budu rád za komentář. Díky

Publikováno pod: .net technology , wpf
21
II

Odpočinkový týden na horách

Neexistuje příliš mnoho okamžiků, na které se pracující člověk těší více, než chvíle, kdy si řekne dost, příští týden si dám odpočinkový. Právě tyto báječné chvíle jsem prožíval minulý týden, který jsem strávil v malebném prostředí a útulném penzionku na rozhraní Jizerských hor a Krkonoš.

Tedy, když se zmiňuji o té malebnosti, je to spíše nadsázka, ale jak se říká, bílou barvou se nic nezkazí a tak jí bylo všude dostatek, hlavně tedy ve vzdálenosti přibližně dvaceti metrů před námi. O něco horší to již bylo pod našimi chodidly, kde se po většinu denního času nacházel černý asfalt. Tudíž jakékoli pomyšlení na sjezdovky nebo na běžky, o tom nemohla být žádná řeč. Teplota někde nad bodem mrazu, byť ne příliš daleko, takže i zbývající sníh byl těžký a mokrý.

Přesto jsem byl nadšen. Možná se teď divíte proč, vždyť to musela být celkem nuda, nic nevidět, nemoci si ani pořádně zalyžovat. Omyl, možná až teď jste si uvědomili, že to není vše, co dělá z dovolené ty chvíle na které se člověk těší.

Atmosféra a společnost, kterou mi dělala manželka a hlavně Davídek, pravda nesmím zapomenout také na rodiče. To je něco neocenitelného, co vytvoří nový rozměr a nový pohled na svět. Obzvláště poté, když vidíte první lezecké krůčky, rozzářený úsměv a nadšený chechot od malého stvoření, které si neustále něco brblá přes dva zuby, je to něco nezapomenutelného a asi i těžko popsatelného. Pocit, který zahřeje a dodá spoustu energie.

Na ta místa se rád budu vracet a to nejen v myšlenkách.

Publikováno pod: personal
21
II

RE: ApplicationContext ještě jednou a lépe

Nakonec uveřejňuji následující text do samostatného příspěvku, trošku více jsem se rozepsal na otázku položenou v komentářích k příspěvku ApplicationContext ještě jednou a lépe. A také proto, že autor dotazu na sebe nezanechal kontakt(?) a tak jej nemohu s odpovědí dát lépe vědět.

Skrytí formuláře při startu aplikace

Ač trošku pozdě přicházím s odpovědí, přeci. Property Visible se nastavuje uvnitř vykonávání metody Application.Run() a to vždy na hodnotu true. Tudíž není možné spustit žádný formulář jako neviditelný. Podotýkám, že se stále bavíme o formuláři, nikoliv jen o zobrazení NotifyIcon.

Není však třeba zoufat, i toto má řešení, byť nevede přes ApplicationContext (nebo jsem jej jen nenalezl). V čem vlastně spočívá problém? Ten je v tom, že formulář při všemožném volání metody Hide() na malou chvilku problikne na obrazovce a to i v okamžiku, kdy se budeme snažit přepsat metodu OnShow.

Řešením tak je umístit formulář v události Load na pozice mimo obrazovku a v metodě OnShow jej následně skrýt. Samozřejmě nesmíme zapomenout na to, jej při následném požadavku na zobrazení napozicovat na určené místo. Např. při doubleclick na NotifyIcon. Osobně se mi líbí myšlenka napozicování formuláře na hodnoty

Left = int.MinValue;
Top = int.MinValue;

Snad tyto informace pomohou a dostatečně jsem zodpověděl položenou otázku.

Publikováno pod: .net technology , code snippet
4
II

ADO.NET a AcceptChanges

Fórum o .net na serveru Builder je v současné chvíli poměrně širokou přehlídkou začátečnických chyb a odpovědí  na ně. Nejednomu začínajícímu programátorovi v .net tak může pomoci vstoupit do světa vyspělých technologií. Stačí jen jediné, prohlédnout si ani ne tak vzdálenou historii a většinou by dotazující se získal odpověď, na svoji ještě nepoloženou otázku, téměř okamžitě. Jelikož jsem autorem poměrně značné části odpovědí na nejen tyto otázky, rozhodl jsem se některé z nich vybrat a uveřejnit je zde, jako takové malé FAQ nebo spíše knowledge-base, aby byly přeci jen lépe dostupné. Byť je možné stále si stáhnout historii konference pro offlline prohlížení.

DataSet.AcceptChanges a neukládání dat

Poměrně častým dotazem je, proč se nechtějí ukládat data do datového zdroje, přestože jsou vidět v datasetu a nad tímto je prováděn Update pomocí DataAdapteru, případně ve verzi .net 2.0 pomocí TableAdapteru.

Ona záludnost tkví v tom, že začátečník, snažící se o zapsání všech dat volá všechny metody, na používaných objektech. Tudíž velice správně zavolá metodu EndEdit() pro zapsání editovaných změn do datového objektu většinou DataSetu.

Co je však již špatně, zavolání metody AcceptChanges() nad tímto DataSetem ještě před provedením zapsání změn do datového zdroje. Vykonáním této metody totiž dojde k akceptování všech změn (jak je také patrné z názvu metody) a nastavení stavu všech řádků v jednotlivých tabulkách na hodnotu DataRowState.Unchanged. Následné volání metody Update() nad TableAdapter/DataAdapter potom nemá jak poznat, které řádky má aktualizovat, vložit nebo smazat a neprovede tak žádnou akci.

AcceptChanges tedy není nutné volat

a to v případech, kdy zapisujeme data do datového zdroje, neboť tuto metodu zavolá DataAdapter/TableAdapter sám, po provedení zápisu změn do databáze.

Publikováno pod: .net technology , builder.cz , knowledge base
24
I

ApplicationContext ještě jednou a lépe

Udělat chybu je celkem lidské, že to však dopadne takto jsem tedy vůbec nepředpokládal. Když jsem nedávno psal o splash screenu a jak jej zobrazit za pomoci třídy ApplicationContext vůbec jsem netušil, jaký to bude mít dopad a že něco není v pořádku.

Chyba není na vašem přijímači

To jediné mě malinko uklidňuje, že chyba není ani na vašem a kupodivu ani na mém přijímači. Tedy samozřejmě v přeneseném slova smyslu (je třeba si za tím představit napsaný kód). A o jakou vlastně chybu se jedná? Při použití SaveFileDialogu a pokusu o přepsání již existujícího souboru by se měl objevit dialog zda chceme soubor přepsat. Místo toho však aplikace vyvolá vyjímku Cannot access a disposed object named "FormSplash". S výpisem tohoto Stack trace:

-----[Core exception]--------------------
at System.Windows.Forms.Control.CreateHandle()
at System.Windows.Forms.Form.CreateHandle()
at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.ThreadWindows.Callback(IntPtr hWnd, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.EnumThreadWindows(Int32 dwThreadId, EnumThreadWindowsCallback lpfn, HandleRef lParam)
at System.Windows.Forms.ThreadWindows..ctor(Control parent, Boolean onlyWinForms)
at System.Windows.Forms.ThreadContext.DisableWindowsForModalLoop(Boolean onlyWinForms)
at System.Windows.Forms.ThreadContext.BeginModalMessageLoop()
at System.Windows.Forms.Application.BeginModalMessageLoop()
at System.Windows.Forms.MessageBox.ShowCore(IWin32Window owner, String text, String caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options)
at System.Windows.Forms.MessageBox.Show(String text, String caption, MessageBoxButtons buttons, MessageBoxIcon icon)
at System.Windows.Forms.FileDialog.MessageBoxWithFocusRestore(String message, String caption, MessageBoxButtons buttons, MessageBoxIcon icon)
at System.Windows.Forms.SaveFileDialog.PromptFileOverwrite(String fileName)
at System.Windows.Forms.SaveFileDialog.PromptUserIfAppropriate(String fileName)

To je, zjednodušeně řečeno, způsobené tím, že smyčka zpráv se vytvořila nad formulářem FormSplash a přestože došlo následně k přiřazení hlavního formuláře do property MainForm ve třídě ApplicationContext v přepsané metodě OnMainFormClosed, smyčka zpráv se nepředala a zůstala nad již zavřeným formulářem.

Finální řešení

Mohli bychom samozřejmě provádět ještě šílenější obezličky než za chvíli zmíněné řešení, ale proč. Určitě je možné zobrazovat Splash screen v obsluze události Load hlavního formuláře, nebo vymyslet ještě obskurnější řešení, většinou však tato řešení budou poměrně hodně svázána s konkrétním hlavním formulářem a nebude tak možné mít jednu obecnou třídu pro zobrazení Splash screenu.

Navržené řešení je triviální, leč ne úplně čisté a děkovat za něj mohu dobrému pomocníkovi Reflectoru. Je totiž nutné přenastavit interní proměnnou currentForm ve třídě ThreadContext, která je interní třídou v ApplicationContext.

Část kódu, který je tedy přítomen v metodě OnMainFormClosed vypadá následovně a prosím všechny ty, kteří použili mnou navržené řešení, o opravu v jejich kódu:

_main = new FormMain();
Type application = typeof(Application);
Type threadContext = application.GetNestedType("ThreadContext", BindingFlags.NonPublic);
object current = threadContext.InvokeMember("FromCurrent", BindingFlags.Static | BindingFlags. NonPublic | BindingFlags.InvokeMethod, null, null, new object[0]);
FieldInfo currentForm = threadContext.GetField("currentForm", BindingFlags.NonPublic | BindingFlags.Instance);
currentForm.SetValue(current, _main);
this.MainForm = _main;
this.MainForm.Show();

Proč považuji toto řešení za ne úplně čisté je celkem jasné, je využívána reflection, což by samo o sobě vadit nemělo, avšak je nutné uvést textově odkazy na získání interních proměnných, jejichž název se může v příští verzi změnit.

Po provedení této úpravy by se aplikace měla chovat tak jak očekáváme a tak jak jsme ji napsali.

Publikováno pod: .net technology , code snippet