C# WPF Aplikace - Converter2 [UPDATE]

V předchozím článku jsem popisoval jak snadno se díky WPF technologii dá udělat protoyp jednoho prográmku na přepočet jednotek. Pokud jste si zdrojáky použitého konvertoru prohlédli, víte, že výpočet převodu je opravdu jeden vzoreček. Nádhera. Celkem funkční aplikace a nemusel jsem skoro vůbec programovat.

Jenže jsem si řekl, že takovou aplikaci bych chtěl ještě rozšířit. Tak například bych chtěl aby aplikace získala následující rysy:

 

  • XML s daty by měl stát samostatně jako soubor u EXE aplikace, aby bylo možné měnit jeho obsah a mít tak možnost si rozšířit možnosti aplikace.
  • V předvolbách nastavit které skupiny veličin chci a nechci používat. Toto nastavení mít tvalé.
  • Chtěl bych po vzoru Joshovi aplikace přehazovat zvolenou vstupní a výstupní jednotku a to například na klávesovou zkratku CTRL+I (jako invertovat) nebo z menu.
  • Na klávesu CTRL+C a menu zkopírovat vypočítanou hodnotu do klipboardu.
  • Chci maličko vylepšit GUI tak, aby bylo přehlednější.
  • Chci aby si záložky po překliknutí pamatovaly původní umístění v listboxech.
  • About dialog by si mohl některé informace o aplikaci zjistit sám, například verzi, copyright.
  • V about dialogu by měly být klikací odkazy na web a na email.

Z výše uvedeného plyne potřeba použít další znalosti možností WPF a C#. Hledal jsem místo, kde bych mohl ozkoušet LINQ, aby to mělo praktický rozměr. LINQ se mi hodil hned několikrát. XML soubor se v aplikaci pomocí objektu XDocument načte a pak následně přes LiNQ se vytvoří kolekce se závislostmi. Pro interpretaci dat v XML souboru jsem vytvořil několik maličkých objektíčků. Objekt Unit udržuje informace o jednotlivé jednotce (veličině). Objekt Kind odpovídá záložce, tedy skupině veličin a obsahuje dva seznamy pro listoboxy. Inputa Output. Z XML jsem chtěl vyčítat seznamy jednotek jen jednou a proto objekt Unit implementuje rozhraní ICloneable. Diky LINQ pak vytvoření seznamu s typy jednotek a zároveň vnořených seznamů jednotek pro listboxy zajistí takováto pěkná konstrukce: (více okolo ní se dozvíte ze zdrojových kódů, na které je odkaz níže)

IList<Kind> kinds;
// Přes LINQ vytáhnu data z XML a naláduju je do kolekcí objektů Kind a Unit.
kinds = (from knds in xdoc.Element("ConversionReceipt").Element("Kinds").Elements("Kind")
            where !excludedKinds.Contains(knds.Element("Name").Value)
            select new Kind
            {
                Name = knds.Element("Name").Value,
                // Setter pro IntputUnits nastavi pomoci klonovani hodnotu pro OutputUnits.
                // Proto zde ctu data ze XML jen jednou.
                InputUnits = (from unts in knds.Elements("Unit")
                            select new Unit
                            {
                                Name = unts.Element("Name").Value,
                                Short = unts.Element("Short").Value,
                                Ratio = decimal.Parse(unts.Element("Ratio").Value.ToString(), System.Globalization.CultureInfo.InvariantCulture),
                            }).ToList(),
            }).ToList();

Ikdyž LINQ umí vytvářet anonymní typy, šel jsem cestou vlastní implementace, protože později v implementaci potřebuji mít typy známé. Navíc dialog Preferences umožňuje resetovat viditelnost jednotlivých záložek, což je v GUI řešeno jako listbox s položkami obsahujícími checkbox. Objekt KindSetup (podobně jako Kind, ale pro účely dialogu Prefrnces) má vlastnost Visibility, která je mapovaná právě na zmíněný chceckbox. Když metoda buttonReset_Click nastaví hodnotu true do všech položek, je nutné aby i v listboxu se přenastavily všechny checkboxy, proto objekt KindSetup implementuje rozhraní INotifyPropertyChanged. To by u anonymního typu nešlo.

Ve snipetu výše je navic dobře vidět konstrukce pro omezení výběru ze XML pomocí příkazu WHERE, kde pracuji s jinou kolekcí, která obsahuje názvy skupin jednotek, které uživatel vidět nechce. Proto se vyloučí z kolekce kind. To je moc pěkná ukázka jak snadno a efektivně lze pracovat s kolekcemi. Kolekce excludedKinds má svůj zdroj v nastavení aplikace. Definoval jsem pro user-scope položku s názvem ExcludeKinds a její typ definoval jako Specialized.StringCollection.

Při načítání XML do kolekcí provádím konverzi koeficientů z textu na typ decimal a proto je i maličko jiná implementace convertoru RatioConverter.

Za zmíňku stojí i objekt AppCommands, jenž vznikl abych si ozkoušel jak pracuji commandy ve WPF. Commandy jsou výborná věc a aplikace Converter2 je příliž maličká aby v ní commandy vynikly. Command by se dalo říct zastupuje task na úrovni aplikace. Lze ho volat z různých míst, například z kódu, z menu, z tlačítka, klávesovou zkratkou. V aplikaci Converter2 je několik commandů a například klávesová zkratka CTRL+C, CTRL+I a ALT+X jsou gesta přiřazená ke commandům.

Aplikaci jsem realizoval abych natrénoval co jsem se naučil, pokud by mohla její implementace být pro někoho inspirací nebo návodem, račte použít, nahlédnout. Zdrojáky jsou opět plné komentářů aby byla funkčnost jasná.

Zdrojové kódy jsou zde.

Aktualizováno (4.4.2012):

Archiv byl občerstven a navíc obsahuje složku "doc", v které najdete kompilovanou dokumentaci ve formátu CHM a dále podadresář "doc/html" v které jsou zdroje nápovědy vygenerované nástrojem DoxyGen.
Vygenerovaná nápověda je k okamžitému nahlédnutí také na tomto odkazu.

O dokumentačním nástroji DoxyGen jsem napsal krátký článek,  přečtěte si ho pokud máte zájem zde .

FUVI0111ADANAUL
FREE Joomla! template "Adana"
joomla 1.6 templates by funky-visions.de