VYSOKÁ ŠKOLA POLYTECHNICKÁ JIHLAVA Katedra elektrotechniky a informatiky Obor: Aplikovaná informatika
Aplikace pro evidenci více pracovních činností a kontrolu zadaných údajů bakalářská práce
Jméno a příjmení: Václav Šedivec Vedoucí práce: Ing. Marek Musil
Jihlava 2014
Abstrakt Základem práce je požadavek na aplikaci, která by spolehlivě evidovala odpracované hodiny napříč více projekty. Tyto hodiny má realizovat jako činnosti, které jsou kontrolované na překryvy a na přesahy zadaných limitů pro jednotlivé projekty. To vše je prováděno lokálně a realizováno za využití databáze. Aplikace je postavená na Microsoft .NET Framework za využití jazyka C# a technologií Windows Presentation Foundation (WPF) a Entity Framework (EF). Použitým vzorem návrhu je Model-View-ViewModel. Použité technologie jsou rozebrány teoreticky a následně jejich praktické využití v aplikaci. Jako databáze je použita Microsoft SQL Compact Edition 4.0. Výsledkem je moderní aplikace, která splňuje zadané požadavky a obsahuje další funkce, které usnadňují a zkvalitňují její použití v praxi.
Klíčová slova .NET Framework, C#, Entity Framework, Evidence práce, MVVM, Výkaz práce, WPF.
Abstract Base of this thesis is the need for an application that would reliably and conveniently register the work hours under many work projects. These hours are to be represented by activities which are checked for overlaps and overflows of their project’s limits. That all shall be realized locally with use of database. Application is built on Microsoft .NET Framework using C# and with use of Windows Presentation Foundation (WPF) and Entity Framework (EF) technologies. As design pattern, the Model-View-ViewModel was used. All technologies used in thesis are covered theoretically and then shown on examples from application. For the database, the Microsoft SQL Compact Edition is used. Result of this thesis is a modern application, which realizes all given requests and some other functions, that makes application easier and more convenient to use.
Key words .NET Framework, C#, Entity Framework, MVVM, Timesheet, Work records, WPF.
Poděkování Na tomto místě bych rád poděkoval svému vedoucímu práce Ing. Marku Musilovi za poskytnutí tématu a možnost vytvářet pod jeho vedením.
Obsah 1 Úvod a motivace ............................................................................................................ 8 2 Současný stav ................................................................................................................. 9 3 Zvolený způsob řešení ................................................................................................. 10 4 Principy implementace a používané technologie......................................................... 13 4.1 Windows Presentation Foundation (WPF) ............................................................... 13 4.1.1 Co WPF přináší...................................................................................................... 13 4.1.2 Architektura WPF .................................................................................................. 15 4.1.3 Struktura WPF aplikace ......................................................................................... 16 4.1.4 XAML a kompilace ............................................................................................... 17 4.1.5 Dependency Properties .......................................................................................... 17 4.2 Model-View-ViewModel (MVVM) ......................................................................... 20 4.3 Vlákna a úlohy .......................................................................................................... 22 4.4 Entity Framework ..................................................................................................... 23 5 Realizace ...................................................................................................................... 25 5.1 Rozčlenění projektu .................................................................................................. 25 5.2 EasyWorklogInstaller ............................................................................................... 26 5.3 EasyWorklogLibrary ................................................................................................ 28 5.3.1 Význam .................................................................................................................. 28 5.3.2 Součásti .................................................................................................................. 28 5.3.3 Databáze................................................................................................................. 32 5.3.4 DatabaseWatch ...................................................................................................... 38 5.4 EasyWorklog ............................................................................................................ 41 5.4.1 Datové třídy ........................................................................................................... 41 5.4.2 Obslužné třídy ........................................................................................................ 42 5.4.3 Vlastní ovládací prvky ........................................................................................... 46 5.4.4 Uživatelské prostředí ............................................................................................. 49
5.4.5 Styly ....................................................................................................................... 56 5.4.6 Jazyková lokalizace ............................................................................................... 57 5.4.7 Export do xlsx ........................................................................................................ 60 5.4.8 Další funkce ........................................................................................................... 61 6 Závěr ............................................................................................................................ 63 Seznam použité literatury ............................................................................................... 64 Seznam obrázků .............................................................................................................. 65 Seznam příkladů ............................................................................................................. 66 Seznam tabulek ............................................................................................................... 67 Seznam použitých zkratek .............................................................................................. 68 Přílohy............................................................................................................................. 69 1 Přiložené CD ................................................................................................................ 69 2 Manuál aplikace ........................................................................................................... 70
1 Úvod a motivace Tato aplikace řeší problematiku organizace více souběžně probíhajících pracovních projektů, které mohou být často zmatečné a hlídání jejich překryvu je časově a psychicky náročné. Jednotlivé projekty jsou také ve většině omezeny na maximálním počtu hodin. Potřebou, která mě motivovala k napsání této aplikace, je potřeba jednoduché prostředí, které bude snadno ovladatelné, přehledné a nebude plné složitých textových a kontextových nabídek. Požadavkem je graficky učesaná, jednoduchá aplikace, která umožní snadné sledování projektů a jednotlivých činností v rámci každého projektu. Aplikace upozorní nebo zamezí vzniku časových překryvů a nabídne náhled na zadaná data formou měsíčního výkazu. Také umožní definici časového omezení, kdy nelze zadávat žádné činnosti a poskytne způsob exportu dat mimo aplikaci. Spousta aplikací, které jsou v současnosti na trhu a daly by se alespoň částečně využít pro dané potřeby, jsou zbytečně složité a mají spoustu dalších funkcí, které nejsou vyžadované. Příkladem je Easy CompuDiary, která umožňuje záznam činností, bohatý popis, přidání souborů k událostem, ale neumožňuje evidenci činností seskupených do projektů ani kontrolu překryvu jednotlivých činností.
8
2 Současný stav V současnosti je daný problém řešen hned několika způsoby.
Jednoduchá lokální aplikace
Komplexní, rozsáhlá aplikace
Webová aplikace
Mobilní aplikace
Jednou možností řešení zadané problematiky je jednoduchá lokální aplikace, bez velkého zabezpečení a taková aplikace je určena spíše pro osobní použití. Tuto možnost jsem zvolil jako řešení své bakalářské práce a bude upřesněna v následující kapitole Zvolený způsob řešení. Další možností je komplexní, rozsáhlá aplikace, která by podporovala více uživatelů. Jednotlivé uživatele a jejich docházku/evidenci práce bude držet v jedné, nebo více větších databázích. Databáze se mohou nacházet na webu, v podobě SQL Serveru (Structured Query Language), nebo jako cloud (např. Azure Cloud). Aplikace pak z důvodu bezpečnosti a rozdělení funkcí musí umět více úrovní přístupu = více režimů zobrazení a možností zacházení s daty. Toto řešení se hodí pro firemní použití, je nejrozsáhlejší a nejkomplexnější. Má vysoké nároky na bezpečnost, prostor a s tím i značně rostou nároky výkonové. Také dnes velmi atraktivním, především v povoláních, která nevyžadují denní docházení na pracoviště, je webová alternativa. Jedná se o centralizovanou aplikaci, která je přístupná z jakéhokoliv zařízení, které má kompatibilní webový prohlížeč. Takový systém se komplexností a rozsáhlostí může pohybovat mezi předchozími dvěma případy. Je zde však bezpodmínečně nutné, aby aplikace realizovala víceuživatelský přístup a autentizaci. Webová aplikace, která by měla jen jednoho uživatele, má výhodu v její přenosnosti a zobrazení na velkém množství zařízení. Na stranu druhou se však nevyhneme určitým poplatkům za doménu, prostor a výpočetní výkon, který je nám poskytnut. Pro jedince tudíž nevhodná. Dalším možným řešením je mobilní aplikace. Ta je často v podobě aplikace, která přistupuje k webovým službám a nedrží tudíž všechna data. Mobilní aplikace se také hojně využívají jako doprovodné, odstrojené verze desktopových/webových aplikací.
9
3 Zvolený způsob řešení Jako řešení dané problematiky jsem zvolil možnost jednoduché lokální databázové aplikace. Aplikace firemních rozměrů by byla velmi komplikovanou, ne však neproveditelnou. Aplikace takových rozměrů však často vyvíjí celý tým, jelikož taková aplikace musí pokrýt požadavky mnoha firem, aby jeho uplatnitelnost na trhu byla co nejvyšší. Proto jsem se rozhodl pro jednodušší a svižnější řešení, které má spoustu výhod od nižších požadavků na počet lidí, kteří se budou na vývoji podílet, až po svižnost a jednoduchost, která je pro osobní použití velmi žádanou. Aplikace, kterou jsem nazval „EasyWorklog“ je tedy jednoduchou aplikací která se bude zabývat hlavně těmito problémy:
Evidence pracovních činností
Kontrola kolizí a možnost jejich řešení
Kontrola limitů odpracovaných hodin
Nastavení časových omezení
Aplikace je jedno-uživatelská aplikace typu singleton, což znamená, že může být v jeden okamžik spuštěna pouze jednou. Každý uživatel Windows však má svou vlastní databázi, která je uložena zde: C:\Users\%username%\MyDocuments\EasyWorklog\ClientDatabase.sdf Získání této cesty je popsáno v AppDirectories. Jako databázi jsem se rozhodl použít Microsoft SQL Compact Edition, jelikož nevyžaduje instalaci žádného programu, pouze volně dostupných knihoven, které jsou součástí .NET Framework. Aplikace je napsaná v jazyce C#, s využitím technologie WPF, což zahrnuje jazyk XAML, a návrhovým vzorem, který je více popsán v sekci Model-View-ViewModel (MVVM). Využívat bude taktéž určité knihovny, spojené se zrychlením vývoje WPF aplikací. Jedná se především o Caliburn.Micro a Castle.Windsor.
Caliburn se stará především o provázání View a Viewmodelů projektu.
Windsor implementuje metodu IoC (Injection of Container) a usnadňuje tak vytváření objektů a jejich pozdější úpravy, stejně tak jako nahrazení statických 10
objektů objekty nestatickými, které jsou však přenášeny skrze celou aplikaci a uspokojují tak potřebu singleton objektů.
Hardcodet.TaskbarIcon umožňuje snadné přidání notifikační ikony, která jinak ve WPF chybí a je vytvořena pomocí WPF (nezávislá na třídách přítomných v System.Windows.Forms)
Možnosti a cíle aplikace:
Vytváření pracovních profilů a v jejich rámci evidence pracovních činností
Kontrola kolizí a limitů jednotlivých profilů
Přehledný náhled na záznam v rámci jednoho měsíce a jeho export
Snadné, rychlé a pěkné grafické prostředí
Aplikace uživateli umožní snadno, rychle a přehledně evidovat pracovní činnost. Bude kontrolovat překrývání jednotlivých pracovních činností mezi projekty na základě zadávaného času. Pro usnadnění bude našeptávat již provedené, relevantní činnosti na základě času a projektu, ve kterém se bude uživatel nacházet. Vše se bude ukládat do databáze, která bude typu SQL Compact Edition uloženou do souboru ClientDatabase.sdf. Výchozí požadavky na funkce aplikace jsou následující:
Vytváření, editace a mazání pracovních profilů.
Vytváření, editace a mazání činností pod pracovními profily.
Nastavení limitů na počet hodin v projektu za určité období: o Den o Týden o Měsíc
Automatická kontrola dodržení limitů.
Automatická kontrola kolizí činností napříč profily.
Možnost exportu dat ve formě xlsx souboru.
Možnost nastavení času, v jaký nebude možné činnosti přidávat.
Důvodem, proč jsem zvolil řešení ve formě WPF aplikace, je především volnost, jakou WPF v návrhu grafického prostředí umožňuje. WPF aplikace mohou mít bohaté grafické prostředí plné animací a různých stupňů průhlednosti. Nejen že umožňuje takto bohaté
11
prostředí při zachování výkonu, ale v případě např. Windows Forms bychom průhledného okna dosahovali jen velmi obtížně. Kromě všech jeho výhod, které jsou popsané v následující kapitole Windows Presentation Foundation (WPF), hrají jistou roli i mé zkušenosti s touto technologií. Na obrázku 3.1.1 je vidět hlavní okno aplikace. Na obrázku 3.1.2 je pak ukázáno využití průhlednosti na okrajích okna, které není maximalizované.
Obrázek 3.1.1: Hlavní okno aplikace
Obrázek 3.1.2: Detail na okraj hlavního okna
12
4 Principy implementace a používané technologie 4.1 Windows Presentation Foundation (WPF) Jedná se o novější technologii zahrnutou v .NET Framework. Dříve všechny možné programovací jazyky využívaly dvě hlavní knihovny, pro vykreslení grafického uživatelského prostředí (GUI) a interakci s uživatelem. Konkrétně se jedná o knihovny „user32.dll“ a „GDI/GDI+“.
User32.dll – obsahuje definice vzhledu a funkcí základních elementů, použitých při návrhu GUI, jako jsou okna, tlačítka, textová pole apod.
GDI/GDI+ – stará se o vykreslování složitějších elementů jako jsou tvary, text a obrázky na s cenou vyšší složitosti a často i náročnosti na výkon
Ve WPF je však jedna zásadní změna a to je nahrazení GDI/GDI+ dlouhá léta vyvíjenou knihovnou DirectX, která je hojně využívána v herním průmyslu a postupem času se stala součástí Windows. To má za následek hned několik věcí. Aplikace náhle dostává k dispozici mocnou zbraň – hardware akceleraci. Tím se WPF otevírají nové možnosti, jako je průhlednost, vyhlazování hran (antialiasing), komplexní textury a trojrozměrná grafika. WPF zapojuje DirectX i při nejjednodušších grafických částech GUI. Tím podstatně šetří čas procesoru, protože DirectX předává vše grafické kartě, která je právě pro tento účel optimalizovaná. Nezáleží na síle grafické karty, ani na systému, ať se jedná o Windows XP, Vista, 7, 8 nebo 8.1, grafická část je vždy vykreslována skrze DirectX. WPF aplikace mohou být zpětně kompatibilní se všemi verzemi Windows, které podporují alespoň .NET Framework 3, v kterém byla zahrnuta první verze WPF.
4.1.1 Co WPF přináší WPF s sebou nese mnoho novinek a rozdílů oproti starším Windows Forms.
Návrh grafického modelu podobný webovému
Bohatý model kreslení
Bohatý model textů
Animace jako součást Framework
Lepší podpora videa a audia
Styly a šablony 13
Commands (příkazy)
Deklarativní uživatelské rozhraní
Aplikace založené na stránkách
Místo pevného umístění pomocí souřadnic, pevné šířky a výšky nám WPF umožňuje využít relativního umístění s velikostí závislou na obsahu, jak můžeme znát z programování webových stránek. To umožňuje vysoce dynamické uživatelské rozhraní, které se snadno přizpůsobuje aktuálnímu obsahu. Elementy nejsou definovány jednotlivými pixely, ale poskládány z menších primitivních prvků, jako jsou Ellipse, Rectangle a další. Vykreslování pixelů je sice rychlejší, protože nedochází k výpočtu, ale reprezentace primitivními elementy nám zaručuje ostrost objektu při jakékoliv velikosti a Framework je pro tento účel vysoce optimalizován. Také jsou zde nové možnosti, jako je průhlednost prvků, které lze na sebe navzájem skládat. WPF také umožňuje všude zobrazovat text, který lze nastylovat, rozdělit do sloupců a dál upravit pro nejvyšší možnou čitelnost. Animace zde prodělaly velkou změnu, jelikož jsou nyní součástí Framework a není třeba používat časovačů. Animace pouze deklarujeme v uživatelském rozhraní a o jejich chod se postará WPF samo. WPF dále podporuje spuštění jakýchkoliv video nebo audio souboru, které lze spustit ve Windows Media Player a to hned několik současně. Také například umožňuje zakomponování videa do uživatelského rozhraní, kde s ním lze pracovat jako s jakýmkoliv jiným elementem, např. zobrazit ho na roztočené 3D kostce. Velkou pomocí při vytváření uživatelského prostředí jsou také styly a šablony. Ty nám umožňují deklarovat podobu elementů, která následně může být využívána napříč celou aplikací. Navíc jsou velmi mocným nástrojem, který nám umožní zcela změnit vzhled již existujících prvků, což bylo např. ve Windows Forms obtížně a často nemožné. Novinkou jsou Commands, které nám umožní deklarovat akci na jednom místě aplikace a nasměrovat na ní ovládací prvky z různým míst uživatelského prostředí. Uživatelské rozhraní je serializováno do XML (extensible markup language) příznaků v jazyce XAML (eXtensible Application Markup Language). To ho separuje od kódu aplikace a poskytuje jednoduchou cestu pro grafiky, kteří mohou využít specializované
14
nástroje pro editaci XAML souborů nezávisle na kódu aplikace. k tomu slouží např. Blend for Visual Studio 2013, který je součástí instalace určitých edic Visual Studio 2013. Poslední velmi významnou novinkou, kterou WPF přináší, je možnost jednoduše vyvíjet aplikace, které budou založené na stejných mechanismech jako prohlížeč webových stránek. WPF pak samo obstarává historii prohlížení a umožňuje i spouštění aplikace v Internet Explorer jako kdyby se jednalo o webovou aplikaci.
4.1.2 Architektura WPF Architektura WPF z několika vrstev. Aplikace komunikuje s nejvyšší vrstvou, která je psaná celá v řízeném C# kódu. O překlad do neřízeného kódu, který může být zpracován v Direct3D, se stará knihovna milcore.dll. Ta sama je psaná v neřízeném kódu kvůli vysoké integraci s Direct3D a vysoké náchylnosti na výpočetní výkon.
Obrázek 4.1.1: Architektura WPF [1](str. 11)
PresentationFramework.dll drží typy a ovládací prvky nejvyšší úrovně a implementuje styly. Obsahuje většinu tříd, které programátor využívá.
PresentationCore.dll obsahuje základní typy, jako jsou UIElement a Visual, z kterých jsou všechny tvary a ovládací prvky odvozeny.
WindowsBase.dll má v sobě ještě základnější typy, které jsou použitelné i mimo WPF. Mezi ně patří například DispatcherObject a DependencyObject, které představují základ pro dependency properties (závislé vlastnosti).
15
milcore.dll je jádrem vykreslovacího systému WPF. Překládá uživatelské rozhraní na trojúhelníky a textury, což jsou elementy, které Direct3D očekává.
WindowsCodecs.dll je nízko-úrovňové aplikační rozhraní, které se stará o práci s obrázky.
Direct3D je nízko-úrovňové aplikační rozhraní, které obstarává veškeré vykreslování.
User32 nehraje žádnou roli ve vykreslování WPF, ale stará se o stav aplikací atp., proto je v architektuře WPF zahrnut.
4.1.3 Struktura WPF aplikace Po založení nového projektu WPF aplikace ve Visual Studiu 2013 (dále jen VS) se oproti Windows Forms setkáme hned s dvěma rozdíly. Jedním je přítomnost App.xaml, který nahrazuje Program.cs. App.xaml nám deklaruje třídu s názvem „App“, která se stará o chod aplikace. Hlavním rozdílem proti ekvivalentu z Windows Forms je právě to, že třída App je složena ze dvou parciálních deklarací. Jednou deklarací je samotný soubor App.xaml, který poskytuje místo pro zavedení globálních zdrojů pro všechny části grafického prostředí, které budou v aplikaci vytvořeny. To znamená, že potřebujeme-li zavést např. Converter (převaděč), který nám bude sloužit pro převod formátu dat tekoucích mezi grafickým prostředím a pozadím aplikace a je třeba ho využívat na více místech, pak jsou zdroje v parciální třídě App právě tím místem, které hledáme. Druhou deklarací je pak samotný codebehind v souboru App.cs, který je psaný v jazyce C#. Jelikož je však App odvozena z Application, která není odvozena z třídy Visual, tak v ní nelze deklarovat jakýkoliv obsah. Slouží pouze jako prostředek pro deklaraci zdrojů pro části uživatelského prostředí. Dalším rozdílem je samotné hlavní okno aplikace, které je rovněž složeno ze dvou částí, konkrétně MainWindow.xaml a MainWindow.cs. Zde je však parciální třída MainWindow odvozena z třídy Window, tudíž jí již lze plnit obsahem uživatelského prostředí. Codebehind ve formě MainWindow.cs pak lze využít jako zdroj dat, anebo k ovládání stavu uživatelského prostředí. Jako kořenový prvek se kromě třídy Application nebo Window může ve WPF aplikaci vyskytovat také Page, v případě aplikace založené na stránkách.
16
4.1.4 XAML a kompilace Rozdílem v kompilaci oproti např. Windows Forms je pak především co se děje s XAML soubory. Jazyk XAML byl vyvinut s ohledem na logičnost, snadnou čitelnost a přehlednost kódu. Takový kód je však dlouhý a neoptimalizovaný. Proto se při kompilaci soubory XAML převádějí do BAML, což není nic jiného, než binární ekvivalent jazyka XAML. BAML je však na rozdíl od jazyka XAML optimalizovaný jak v délce, tak i s ohledem na výkon při parsování za chodu aplikace. Kompilovaný BAML je pak veden jako Embedded Resource ve výsledném EXE nebo DLL souboru.
4.1.5 Dependency Properties DependencyProperty (dále jen DP) vycházejí ze standartních vlastností, které jsou nedílnou součástí .NET Framework. Standartní vlastnosti obohacují např. o upozornění na změnu hodnoty, podporu pro přednastavené hodnoty a jejich dědičnost v objektovém stromu. Stávají se tak základem pro hned několik základních funkcí WPF, jimiž jsou animace, data binding a styly. DP jsou navrženy tak, že se využívají stejným způsobem jako standartní vlastnosti. Kdyby však chtěl vývojář rozšířit standartní vlastnosti o možnosti, které poskytují DP, jeho kód by se značně rozrostl a rostla by tím i rizika chyb a dopad na výkon aplikace. DP jsou navrženy s ohledem na nejvyšší možnou optimalizaci při zachování požadované funkcionality. I když je lze v kódu využívat stejným způsobem, jako je tomu u normálních vlastností, jejich deklarace je zcela odlišná a stejně tak podmínka pro jejich implementaci. Samotnou podmínkou je, že DP lze využít jen ve třídách, které jsou potomky DependencyObject. DP se deklaruje jako „static readonly“ objekt třídy. Objekt samotný pak nezískáme zavoláním konstruktoru, jelikož DP nemají přístupný konstruktor, ale zavoláním přetížené statické metody DependencyProperty.Register(…). v příkladu 4.1.1 je ukázána deklarace
veřejně
přístupné
DP,
která
je
typu
string,
náleží
třídě
DependecyPropertyExample, její přednastavená hodnota je „text“, jmenuje se ExampleProperty a je registrována pod jménem „Example“.
17
public static readonly DependencyProperty ExampleProperty = DependencyProperty.Register( "Example", typeof(string), typeof(DependencyPropertyExample), new PropertyMetadata("text") );
Příklad 4.1.1: Deklarace DependencyProperty
Deklarace je tedy zcela odlišná od normální vlastnosti. Na takto deklarovanou již lze navázat GUI pomocí data binding. Pro přístup z kódu, který by byl konzistentní s již známým přístupem k vlastnostem jen třeba využít právě vlastností samotných. Potřebná konstrukce
pro
DP
z příkladu
4.1.1
je
pak
uvedená
v příkladu
4.1.2.
public string Example { get { return (string)GetValue(ExampleProperty); } set { SetValue(ExampleProperty, value); } }
Příklad 4.1.2: Potřebná konstrukce DependencyProperty
V příkladu 4.1.2 pak vidíme, že pro přístup k hodnotám v naší DP je třeba využít metod GetValue a SetValue, které jsou zděděné z DependencyObject. Lze si také povšimnout konvence v pojmenování DP. DP ExampleProperty má stejný název jako vlastnost, skrze kterou se k ní přistupuje, avšak s „Property“ přidaným na konci. To zamezí kolizi s názvem obslužné vlastnosti pro přístup z kódu, která pak může být shodná s názvem pod kterým je DP registrována, jímž je samotné „Example“. Z toho plyne, že název DP samotné reprezentuje objekt, který drží všechna data dané DP. Název, který je uvedený v našem příkladu 4.1.1 jako první parametr funkce Register, je označení, pod kterým je hodnota v DP přístupná z GUI. a posledně název vlastnosti v příkladu 4.1.2 nám udává, pod jakým jménem budeme k hodnotě v DP přistupovat z kódu. Pro jednoduchost a přehlednost jsou poslední dva totožné. Jelikož však vizuál nepřistupuje k hodnotě v DP skrze námi přidanou vlastnost Example, pak je nevhodné jakkoliv upravovat setter nebo getter za účelem validace nebo konverze. Pro takový případ je potřeba provést přepsání zděděné metody OnPropertyChanged a v ní provést požadované kroky. To lze vidět v následujícím příkladu 4.1.3, kde v případě, že novou hodnotou je prázdný řetězec nebo null, nastaví hodnotu zpět na předchozí hodnotu.
Příklad 4.1.3: Přepis virtuální metody OnPropertyChanged
Hodnoty se v DP ukládají jako object, proto je třeba je před použitím vždy přetypovat. Závislost Nyní se dostáváme k důvodu označení DP (závislá vlastnost). Hodnota, kterou DP vrací, totiž závisí na několika vlastnostech, které WPF při požadavku na hodnotu DP prochází. Jednotlivé vlastnosti jsou následující, seřazeny podle priority vzestupně:
Přednastavená hodnota obsažená v metadatech
Hodnota získaná dědičností
Hodnota daná základním style
Hodnota daná stylem projektu
Hodnota lokální
ValidationCallback DP rovněž podporují registraci ValidationCallback, který je volaný při nastavení hodnoty a určuje výsledek metody IsValidValue. ValidationCallback je volán ještě před zahlášením změny hodnoty. Registrovaná metoda musí přijímat jeden parametr s novou hodnotou a vracet výsledek validace typu bool. CoerceCallback CoerceCallback slouží k upravení (korektuře) hodnoty ještě před zavoláním ValidationCallback. DependencyObject
Registrovaná
metoda
v parametrech
o změně
a data
DependencyPropertyChangedEventArgs.
přijímá
Tato
funkcinalita
objekt
hodnoty je
např.
typu typu
využita
u ProgressBar, kde při změně DP Maximum nebo Minimum je nová hodnota kontrolována právě vůči té druhé.
19
4.2 Model-View-ViewModel (MVVM) MVVW metodika je obecně nejpoužívanější metodikou pro vývoj WPF aplikací. Základní myšlenkou MVVM metodiky je udržet projekt rozdělený na 3 části. Tyto tři části jsou:
View
ViewModel
Model
Obrázek 4.2.1: MVVM [4]
Model Model je ta část aplikace, která se stará o realizaci účelu, za kterým je aplikace vyvíjená. Model obsahuje datové typy, funkce a další elementy nezbytné pro chod aplikace. Při vývoji WPF aplikací je model psán převážně jazykem C#. Může rovněž obsahovat SQL script soubory, které se spouští nad danou databází a jsou hojně využívané při verzování. Nejčastěji se však setkáme právě s jazykem C#. View View je uživatelské prostředí. ve WPF je psané převážně jazykem XAML, ale vyžívá také tzv. „codebehind“. Preferované je však psát grafické prostředí čistě v XAML, jelikož je pak pro grafiky snadné využít pomocné programy, jako je Microsoft Blend, který nabízí
20
bohaté grafické rozhraní určené právě pro editaci a vývoj grafické části aplikace. Některé věci však vyžadují zásah do codebehind. ViewModel ViewModel je poslední a zásadní částí. Stará se vlastně o komunikaci a předávání dat mezi Model a View v případě, že má aplikace data zobrazovat uživateli a umožnit mu jejich editaci. ViewModel, jak již název napovídá, není ani grafickým rozhraním, ani modelem realizujícím aplikační logiku. ViewModel slouží především k navázání a propojení grafického prostředí a aplikační logiky, i když i zde dochází k nutným výjimkám. Výhody a nevýhody MVVM Největší výhodou MVVM přístupu k vývoji aplikací je oddělení aplikační logiky a grafického rozhraní. Logika je tak na grafickém prostředí zcela nezávislá a lze ji tak snadno přenášet mezi jednotlivými aplikacemi nebo realizací jedné aplikace ve více prostředích. Jako příklad bych zde vykreslil aplikaci, která by ukládala informace o daném uživateli. Uživatel by chtěl přistupovat k datům z mobilního telefonu, z aplikace nainstalované na osobním počítači a zároveň občas i z počítače své kolegyně. Realizace by tedy vyžadovala napsání jedné aplikace pro mobilní telefon, další aplikace pro operační systém a třetí aplikace pro webové rozhraní. V případě, že všechna daná zařízení podporují např. .NET Framework 4, pak nejrozumnější možností je právě oddělení grafické a logické části. Logická část se vygeneruje kupříkladu jako knihovna, na kterou bude mít referenci každá z těchto aplikací, a jediné co bude třeba v každé aplikaci napsat znovu, je grafické rozhraní a její propojení s částí logickou. Tímto způsobem se tedy uspíší vývoj aplikace pro různá zařízení, nebo i různá použití, a zároveň se takto vyvarujeme duplicity kódu, chyb vzniklých přepisem, nebo rozšiřováním logiky. Nevýhodou je, že ne vždy je možné tuto metodu dodržet a vznikají situace, které nás nutí k jistým ústupkům. WPF si například neporadí s dynamickými hodnotami pro animace. Hranice musí být v případě animací deklarovaných v XAML předem dané. Jediným
21
způsobem je vytvořit animaci s aktuálními hodnotami za chodu aplikace v codebehind a ručně ji spustit.
4.3 Vlákna a úlohy Každá WPF aplikace využívá STA model (single-threaded affinity), který znamená, že běží v jednom hlavním STA vlákně, které vlastní celé GUI. Aplikaci, která zpracovává větší množství dat nebo úloh lze napsat jako jedno-vláknovou. Taková aplikace však bude při nejlepším trhaná, při nejhorším ji po chvilce Windows vyhodnotí jako aplikaci, která neodpovídá a bude se dožadovat jejího ukončení. K tomu dojde především z toho důvodu, že bez vytvoření paralelního vlákna se vše zpracovává na hlavním vlákně. Proto dlouho trvající operace prováděná na hlavním vlákně způsobí, že aplikace přestane obsluhovat GUI, dokud operace neskončí. Proto se více vláknům při časově náročnějších operacích nevyhneme. V sekci Realizace se nejednou zmíním o metodě, která běží asynchronně, proto zde popíšu základy vláken a nutnost jejich využití při vývoji nejen WPF aplikací. Podstata více vláknové aplikace Vlákno je základem každé více vláknové aplikace. Může zpracovávat informace paralelně s jiným vláknem. Každému běžícímu vláknu je vyhrazen určitý strojový čas. Když budeme mít pro jednoduchost jedno-jádrový procesor, který umí zpracovávat pouze jedno vlákno v jeden okamžik, pak se při průběhu dvou vláken výkon dělí. Vlákna se na daném procesoru střídají, o což se stará plánovač vláken (thread scheduler) s frekvencí závislou na operačním systému. Základní třídy Hlavními třídami, s kterými se setkáme při psaní více vláknové aplikace, jsou:
Thread
ThreadPool
Task
Thread je základní třídou, která zastupuje právě jedno vlákno. Bezparametrickým konstruktorem získáme objekt, který reprezentuje jedno bezejmenné vlákno, které poběží v popředí. Chod v popředí znamená, že aplikace při vypnutí čeká na jeho dokončení.
22
Každé vlákno však vyžaduje určitou režii na vytvoření, uložení do paměti, chod a uklizení po dokončení. ThreadPool (fond vláken) je, jak již název napovídá, třída, která zastupuje zdroj vláken, které se generují tzv. „on demand“ (na vyžádání). Jedná se o statickou třídu, které lze nastavit minimální a maximální počet vláken. Ta se pak stará o recyklaci vláken, což snižuje režii o vytváření a uklízení vláken. Této třídě se pak registruje úloha, která se má provést a o zbytek se postará ThreadPool. Nevýhodou by mohlo být, že vlákna běžící v ThreadPool jsou vždy vlákna běžící na pozadí. Pokud bychom potřebovali před koncem vyčkat dokončení všech vláken, pak bychom museli ošetřit dokončení vláken jinak. Třída Task (úloha) je součástí .NET Framework od verze 4.0. Instance třídy Task využívají TaskScheduler, který řídí jejich činnost, což je v podstatě ekvivalent k ThreadPool. v porovnání jsou však úlohy v kódu přehlednější a jejich použití jednoduší a s vyšší flexibilitou.
4.4 Entity Framework Entity Framework (dále jen EF) je Object/Relational Mapping (dále jen ORM) framework. Umožňuje programátorům přístup k datům na vyšší abstrakční úrovni. EF převádí relační data na model doménově specifických objektů, nad kterými pak programátor provádí potřebné operace. Tím odpadá nutnost vytváření infrastruktury pro čtení, vytváření, aktualizaci a mazání dat např. z relační databáze, jelikož o to vše se stará EF skrze Entity Data Model (dále jen EDM). To programátorovi značně usnadňuje práci a programátor pak může věnovat více času a pozornosti vývoji aplikaci samotné, která nad danými daty operuje. Entity Data Model (EDM) EDM je model, který popisuje logické schéma nejčastěji relační databáze. Za tím účelem přináší:
Entity Types – samotné entity, které jsou objektovým obrazem datových struktur a jsou seskupovány do Entity Sets
Relationship Types – vztahy mezi jednotlivými Entity Types, seskupující se v Relationship Sets
23
Logické schéma databáze je pak mapováno k EMD. Data o mapování jsou ve formě souboru a lze jej psát ručně, nebo využít některý z mapovacích nástrojů. Tato metadata jsou pak využita např. právě při sestavování SQL SELECT, CREATE, UPDATE a DELETE příkazů. Možnosti implementace EF Entity Framework 4.1 a vyšší v kombinaci s nástrojem Visual Studio 2010 a vyšší nabízí celkem 3 možné postupy ve využití EF.
Code first – Zde programátor nejdříve vytvoří tzv. POCO třídy, se kterými bude aplikace pracovat a na základě nich se následně vygeneruje EDM a databáze. S vytvořením a editací EDM tak programátor vůbec nepřichází do styku.
Model first – v tomto případě programátor využije EDM editor, kde vytvoří jednotlivé entity a vztahy mezi nimi. EDM následně vygeneruje entity a databázi.
Database first – Zde je nejprve vytvořena databáze včetně všech tabulek a relací. Z databáze je následně vygenerován EDM a entity.
24
5 Realizace 5.1 Rozčlenění projektu Projekt samotný jsem rozdělil do tří podprojektů:
EasyWorklogInstaller
EasyWorklogLibrary
EasyWorklog
Tyto části následně popíšu, jejich jednotlivým detailům se budu věnovat blíže v částech EasyWorklogInstaller, EasyWorklogLibrary a EasyWorklog. EasyWorklogInstaller Projekt EasyWorklogInstaller se stará o kontrolu a doinstalování knihoven potřebných pro spuštění a chod aplikace. EasyWorklogLibrary Knihovna EasyWorklogLibrary je základní částí, která obsahuje model databáze, přenos dat mezi databází a aplikací a další záležitosti, které nejsou závislé na platformě jako operačním systému, ale pouze na .NET Framework. EasyWorklog Jedná se o projekt realizující samotnou aplikaci. Součástí projektu je grafická část aplikace a její funkční část, která není zahrnutá v knihovně. Aplikace se stará především o zobrazení stávajících dat, které zobrazuje pomocí náhledů. Dále také inicializuje a řeší vyhledávání kolizí. Také poskytuje dva možné náhledy stávajících dat, které lze třídit a následně exportovat do xlsx souboru. Součástí je také náhled nastavení aplikace, kde se naskytuje možnost aplikaci upravit.
Ještě před popisem jednotlivých částí bych rád podotkl, že se budeme hojně setkávat s anglickým jazykem. Zastávám názor, že anglický jazyk, jakožto nejrozšířenější a nejpoužívanější na poli ne jen vědeckém a technickém, je nejvhodnějším prostředkem pro pojmenovávání, komentáře a veškerý popis kromě lokalizované dokumentace. To nám zaručí nejen jistou konzistenci a čitelnost kódu, ale je to také dobrým zvykem z hlediska možnosti spolupráce na nadnárodních projektech, práce pro cizí firmy nebo jakákoliv jiná forma práce, ve které přichází do kontaktu více osob různých jazyků. 25
5.2 EasyWorklogInstaller Význam EasyWorklogInstaller je nutný pro kontrolu nainstalovaných knihoven. Aplikace EasyWorklog vyžaduje pro spuštění a její chod tyto komponenty:
Microsoft.NET Framework 4.5
Microsoft SQL Compact Edition 4.0
Open XML SDK 2.0 pro Microsoft Office
Instalace samotné aplikace EasyWorklog si dokáže ověřit přítomnost potřebné verze .NET Framework. Způsob, jakým je instalátor řešený, však nepovoluje kontrolu speciálních knihoven. Z toho důvodu je nutné tyto knihovny kontrolovat a doinstalovat před instalací EasyWorklog. To je náplní práce právě EasyWorklogInstaller. Součásti Instalátor je jednoduchá aplikace, jejíž rozsah je tak malý, že se nevyplatí implementace MVVM návrhového vzoru. Aplikace tak sestává z dvou náhledů, kde jeden náhled je pro hlavní okno a druhý pro dialogové okno. MainWindow (hlavní okno) Náhled pro hlavní okno je jednoduchý, sestává ze tří kontejnerů typu „Grid“, které fungují jako jednotlivé stránky průvodce instalací – úvod, instalace a ukončení. Veškerá funkční i logická část ověřování a spouštění potřebných instalátorů je v codebehind hlavního okna. DialogWindowView (dialogové okno) Náhled pro dialogové okno, které je využíváno pro získání volby vybrané uživatelem. Zde pouze v případě ukončení aplikace před dokončením instalace. DialogWindowView využívá DialogWindowViewModel, protože tento kód je převzatý z hlavní aplikace, upravený pouze v důsledku absence knihoven přítomných v hlavní aplikaci. Lokalizace Instalátor je z důvodu jednoduchosti a univerzálnosti v anglickém jazyce. Je však připravený pro prípadnou lokalizaci. Provedením lokalizace se budu zabývat v části popisu projektu 5.4 EasyWorklog. 26
Popis funkce Po spuštění aplikace se zobrazí úvodní stránka seznamující uživatele se svým záměrem, viz obrázek 5.2.1.
Obrázek 5.2.1: Úvod instalace
Instalace započne po kliknutí na tlačítko „Install“. Při instalaci se zkontroluje přítomnost následujících knihoven:
Microsoft SQL Compact Edition 4.0 – Přítomnost této knihovny je zjištěna testem
přítomnosti
níže
uvedeného
klíče
v registrech
Windows.
„SOFTWARE\Classes\Microsoft.SQLSERVER.CE.OLEDB.4.0“. V případě neexistence je nabídnuta instalace verze, která je součástí instalátoru jako „Embedded Resource“.
Open XML SDK 2.0 pro Microsoft Office – přítomnost této knihovny je zjištěna testem klíče „SOFTWARE\Classes\Installer\Assemblies“ a v něm hodnoty „C:|Program Files (x86)|Open XML SDK|V2.0|lib|DocumentFormat.OpenXml.d ll“ v registrech Windows. V případě neexistence je nabídnuta instalace verze, která je rovněž součástí instalátoru jako „Embedded Resource“.
Obrázek 5.2.2: Kontrola přítomnosti knihovny Open XML SDK 2.0
Po kontrole a případném doinstalování chybějících knihoven se stáhne a spustí instalátor samotné aplikace EasyWorklog. Tím končí život aplikace EasyWorklog Installer.
27
Obrázek 5.2.3: Dokončení instalace
Požadavky pro spuštění Pro spuštění instalátoru je nutné mít nainstalovaný Microsoft.NET Framework 4.5 nebo vyšší. Pokud není přítomen, ale je podporován, tak je nabídnuta jeho instalace.
5.3 EasyWorklogLibrary 5.3.1 Význam EasyWorklogLibrary je, jak již zvolený název napovídá, projektem knihovny, která se kompiluje do stejnojmenného souboru EasyWorklogLibrary.dll. Ta je pak součástí projektů na ní závislých. Její význam spočívá především v její závislosti na platformě .NET Framework verze 4.0, nikoliv však na operačním systému. Proto se může stát součástí jakékoliv aplikace, která běží pod .NET Framework 4.0 a vyšší. Jako příklad bych zde uvedl možnost distribuce čtyř aplikací, které by tuto knihovnu využívaly. Jedna aplikace by byla psaná pro Windows, tudíž by sama o sobě využívala s jinými systémovými platformami nekompatibilní knihovny, jako je System.Windows.dll a další. Druhou aplikací by byla aplikace psaná pro Android, která by využívala rozhraní Mono, které umožňuje spouštění .NET kódu na zařízeních se systémem Android. Třetí aplikací by byla aplikace pro iPhone, která by využívala rovněž Mono v kombinaci s Xamarin. Nakonec je zde aplikace pro Windows Phone, která nepotřebuje žádné další knihovny ani rozhraní pro spuštění .NET aplikací, jelikož všechny aplikace na Windows Phone jsou psané pro chod pod platformou .NET Framework. Všechny tyto aplikace, ač každá pro jiný systém, by využívaly tu samou knihovnu, bez jakýchkoliv jejích úprav z důvodu kompatibility.
5.3.2 Součásti Součásti knihovny rozepíšu podle jmenných prostor, ve kterých se jednotlivé třídy, rozhraní a další vyskytují.
28
Jmenný prostor EasyWorklogLibrary V kořenovém jmenném prostoru se nacházejí dvě statické třídy, tři rozhraní a jedna abstraktní třída. Statická třída může využít rozšiřitelnost metod objektů již existujících tříd. Syntaxe takového rozšíření je např. pro DateTime vidět na příkladu 5.3.1. public static int GetDayOfWeekIndex(this DateTime datetime, int startIndex = 0) { switch (datetime.DayOfWeek) { case DayOfWeek.Monday: return startIndex; case DayOfWeek.Tuesday: return startIndex + 1; case DayOfWeek.Wednesday: return startIndex + 2; case DayOfWeek.Thursday: return startIndex + 3; case DayOfWeek.Friday: return startIndex + 4; case DayOfWeek.Saturday: return startIndex + 5; default: return startIndex + 6; } }
Příklad 5.3.1: Rozšíření třídy DateTime
To má za následek, že kdekoliv, kde je deklarováno užití jmenného prostoru, v kterém se tato třída nachází, mají všechny instance DateTime k dispozici tuto metodu. ExtensionsLib Jedná se o statickou třídu, která rozšiřuje třídy DateTime, TimeSpan, char a string a poskytuje doplňující metody.
GetDayOfWeekIndex – rozšiřuje třídu DateTime. Její využití spočívá ve vrácení indexu dne v týdnu, který daný objekt představuje. Příklad: Při zavolání této metody v případě DateTime objektu, který představuje nějaké pondělí, je na výstupu metody „0“. Parametrem typu int lze nastavit startovní index.
GetDayOfWeekIndexInMonth – rošiřuje třídu DateTime. Tato metoda vrací o kolikátý výskyt daného dne v týdnu se jedná v rámci měsíce. Parametrem typu int lze nastavit startovní index.
Intersects – je přetížená metoda, která pracuje buď s objekty typu TimeSpan nebo DateTime. Cílem této metody je porovnání čtyř objektů předaných parametry, ve kterých se vyskytují počáteční a konečný čas dvou časových úseků. Výsledkem této metody je, jestli se dané úseky protínají. Skrze doplňkový parametr lze definovat, zda je povolený překryv okrajů měřených úseků. 29
IsNumeric – je přetíženou metodou, která rozšiřuje třídy char a string. Jejích výstupem je, jestli se v jednotlivých případech jedná o číslo.
PropertyFunctions Jedná se o statickou třídu, která poskytuje statickou metodu pro získání názvu vlastnosti ve formě řetězce znaků z lambda výrazu, kterým je daná vlastnost předána. PropertyObjectBase Je to abstraktní třída, která je využívána jako základ pro třídy objektů, které se využívají ve ViewModel. Implementuje rozhraní INotifyPropertyChanged, které poskytuje způsob, jak informovat View o změně hodnoty některé vlastnosti. Také implementuje rozhraní IDetectChanges, které je využito při detekci změn. IHaveId Rozhraní, které ukládá deklaraci vlastnosti s názvem Id typu T, který je daný deklarací šablony. ICopyFrom Rozhraní, které ukládá deklaraci metody s názvem CopyFrom, která přijímá jako parametr objekt typu T a nic nevrací. ILockable Rozhraní, které ukládá deklaraci vlastnosti IsLocked typu bool, která indikuje, jestli je objekt zamknutý a deklaraci metody Lock. Jmenný prostor EasyWorklogLibrary.Calculations Tento jmenný prostor obsahuje pouze jednu statickou třídu s názvem LimitsChecker. Tato třída dává k dispozici tři statické metody pro práci s limity.
TicksOutsideLimits – přijímá skrze parametry pole limitů, pole činností a jednu konkrétní činnost, která by měla být do pole činností přidána. Výsledkem této metody je přetečení s nejvyšší hodnotou, ke kterému by po přidání činnosti došlo, nebo 0.
IsWithinLimits – je parametrově identická s předchozí metodou. Liší se návratovým typem, kde místo hodnoty vyjádřené objektem typu double vrací pouze bool, jako indikaci, zda k přetečení došlo, nebo ne. Také je rychlejší, jelikož končí již prvním přetečením.
30
PercentUsedInMonth – přijímá jako parametry pole limitů, pole činností a datum, který indikuje, o jaký měsíc se jedná. Výstupem je hodnota typu double, která je v intervalu 0 až 1.
Jmenný prostor EasyWorklogLibrary.DbModel V tomto jmenném prostoru je uložen databázový model ClientDatabase a třída DatabaseWatch, která poskytuje metody pro inicializaci, kontrolu a údržbu databáze. Databázový model rozeberu v sekci Databáze. Složka EasyWorklogLibrary/DbModel/ChangeScripts V případě ChangeScripts se nejedná o jmenný prostor, protože se nikde nevyskytují třídy, které by v ní byly definované. Jedná se však o důležitou složku, jejíž obsahem jsou jednotlivé soubory s příponou „sql“. Jejich využitím se budu zabývat v části DatabaseWatch. Jmenný prostor EasyWorklogLibrary.Data V tomto jmenném prostoru se nachází třídy, které slouží k práci s daty přenášenými mezi databází a aplikací. Nazývají se Data Template Object, zkráceně DTO. Jelikož jsou DTO třídy obrazy korespondujících tabulek v databázi, budu se jejich strukturou zabývat blíže v sekci Databáze. Jmenný prostor EasyWorklogLibrary.Queries Tento prostor zahrnuje rozhraní IQueries, abstraktní třídu Queries, která zmíněné rozhraní implementuje a sedm tříd, které tuto abstraktní třídu rozšiřují. Tyto třídy slouží pro samotné uložení a načtení dat. IQueries Jedná se o šablonové rozhraní. Ukládá definici vlastnosti Get, která musí mít veřejný „getter“. Jejím výstupem musí být pole objektů typu T. Dále ukládá definici metody DeleteData, která přijímá skrze parametr data pole objektů typu T. Jejím cílem je odebrání databázových ekvivalentů předaných objektů. Druhou metodou je UpdateDatabase, která rovněž přijímá skrze parametr data pole objektů typu T. Jejím cílem je uložení změn těchto objektů do databáze, pokud existují. Pokud odpovídající záznam v databázi neexistuje, tak je vytvořen. Rozhraní také deklaruje událost DataChanged, která slouží k upozornění na změnu dat. 31
Queries Queries je šablonová abstraktní třída, která implementuje IQueries. Deklaruje metody a vlastnosti dané rozhraním jako abstraktní s výjimkou události. Také přidává neabstraktní metodu NotifyDataChanged, která zprostředkuje vyvolání události DataChanged. Jmenný prostor EasyWorklogLibrary.Enums Součástí jsou dva výčtové typy a jedna statická třída.
LimitType – výčtový typ, který obsahuje všechny typy limitů.
RestrictionType – výčtový typ, který obsahuje druh časového omezení.
GuidToLimitType – statická třída s jedinou statickou třídou Convert, která přijímá jako parametr objekt typu Guid a vrací odpovídající druh limitu jako LimitType, nebo vyhodí výjimku.
5.3.3 Databáze Jako databázi jsem zvolil Microsoft SQL Compact Edition 4.0. Jedná se o relační databázi, která je uložena jako soubor s příponou „sdf“. Poskytovatelem připojení k databázi je „Microsoft SQL Server Compact Data Provider 4.0“, který je součástí instalace volně dostupného balíčku a ten je zahrnut v instalátoru EasyWorklog Installer. Databáze je z bezpečnostních důvodů přístupná pod statickým heslem, které je součástí aplikace. Jedním z důvodů je uložení databázového souboru ve složce, která se může snadno stát sdílenou. Tudíž je z bezpečnostního hlediska nezbytné, aby databáze byla přístupná pouze z aplikace. Dalším z důvodů je snadná dodatečná implementace zabezpečeného přístupu pomocí hesla daného uživatelem. Relační model databáze Databáze sestává ze sedmi tabulek.
Activities
Limits
Places
Projects
ProjectsLimits
Restristions 32
ScriptsVersion
Z názvů tabulek lze vyčíst, že jednak jsou využívány anglické názvy, na což jsem již na začátku kapitoly Realizace upozorňoval, a také že jsem se rozhodl pro označení používat množná čísla. Databázové schéma je viditelné na ER diagramu (Entity Relationship) na obrázku 5.3.1. Pro ER diagram je využita Martinova notace pro její přehlednost při větším množství atributů. Pro všechny tabulky je zaveden společný atribut Id, který je vždy primárním klíčem (dále jen PK). Tento atribut je typu uniqueidentifier, který jsem zvolil pro jednoduchost použití a zaručenou jedinečnost. Výjimkou je pouze tabulka ScriptsVersion, kde je Id typu int a je využito identity, což znamená automatickou inkrementaci. Změna typu je pro zachování jedinečnosti primárního klíče a zároveň odpadnutí povinnosti řešit jeho hodnotu, jelikož PK není nijak využit. Bylo by možné ho opomenout, ale z hlediska zachování určitých formalit a mnou zvolené formy jsem se rozhodl pro jeho zavedení. Dále jsem použil konvence označení pro cizí klíč (dále jen FK) složením jednotného čísla názvu tabulky, která je odkazována a název sloupce, který je primárním klíčem. Jelikož jsem pro všechny tabulky zavedl stejné označení PK, je tím zaručena konzistence označení FK.
33
Obrázek 5.3.1: ER diagram
Activities Tato tabulka se skládá z celkem osmi atributů – z nich jeden PK a dva FK.
Id – jedná se o PK tabulky typu uniqueidentifier.
Description – atribut typu nvarchar o délce 100 znaků. Je využit k popisu činnosti.
StartDate – atribut typu datetime. Označuje začátek činnosti.
EndDate – atribut typu datetime. Označuje ukončení činnosti a může nabývat hodnoty null, což značí neukončenou činnost.
CustomDuration – atribut typu float. Slouží pro nastavení vlastní délky trvání činnosti. Může nabývat hodnoty null, což znamená, že bude brána skutečná vypočtená hodnota.
RealDuration – atribut typu float. Slouží pro uložení skutečné vypočtené hodnoty. 34
ProjectId – atribut typu uniqueidentifier. Jedná se o FK odkazující na záznam v tabulce Projects.
PlaceId – atribut typu uniqueidentifier. Jedná se o FK odkazující na záznam v tabulce Places.
V tabulce jsou uloženy všechny činnosti všech projektů. Places Tato tabulka má pouze dva atributy.
Id
Name – atribut typu nvarchar délky 100 znaků. Jedná se o název místa.
Tabulka slouží jako číselník možných míst, na kterých mohou činnosti probíhat. Projects Tabulka sestává z celkem 7 atributů.
Id
Name – atribut typu nvarchar délky 100 znaků. Jedná se o označení projektu.
Abbrev – atribut typu nvarchar délky 100 znaků. Obsahuje zkratku označení.
StartDate – atribut typu datetime. Označuje začátek projektu.
EndDate – atribut typu datetime. Označuje konec projektu a může nabývat hodnoty null, v případě že projekt nemá konec.
LastEdit – atribut typu datetime. Označuje datum poslední změny údajů.
IsDefault – atribut typu bit. Onačuje přednastavený projekt pro nově vytvářené činnosti.
Záznamy této tabulky tvoří jednotlivé projekty, které si uživatel vytvoří. Databáze neřeší duplicitu zvolených názvů nebo zkratek. Limits Tabulka je tvořena pouze dvěma atributy.
Id
Name – atribut typu nvarchar délky 100. Označení limitu.
Jedná se o číselník. Nepřímým omezením, které se ve schématu databáze neprojeví, je nemožnost přidání nebo odebrání záznamů této tabulky. 35
ProjectsLimits Tato tabulka je tvořena pouze jedním PK a dvěma FK.
Id
ProjectId – atribut typu uniqueidentifier. Jedná se o FK, který odkazuje na záznam v tabulce Projects.
LimitId – atribut typu uniqueidentifier. Jedná se o FK, který odkazuje na záznam v tabulce Limits.
Tabulka ProjectsLimits realizuje vztah M:N mezi tabulkami Projects a Limits. Restrictions Tato tabulka je tvořena šesti atributy.
Id
UserId – atribut typu nvarchar délky 100 znaků. v tuto chvíli není jakkoliv využit, je pouze připraven pro rozšíření o podporu více uživatelů.
StartDate – atribut typu datetime. Označuje začátek vyhrazeného intervalu.
EndDate – atribut typu datetime. Označuje ukončení vyhrazeného času.
RepeatType – atribut typu int. Značí, o jaký typ opakování se jedná.
Description – atribut typu nvarchar délky 100 znaků. Obsahuje popis omezení.
Restrictions slouží k uložení vymezeného času. Více o omezeních bude probráno v kapitole RestrictionsMaster. Entity Data Model EDM je v tomto případě generováno na základě již existující databáze. EDM následně generuje třídy, které jsou obrazy databázových tabulek. Typy jednotlivých členů jsou generovány pomocí převodu databázových typů na základě tabulky 5.3.1.
36
Databázový typ
C#.NET typ
bit
Boolean
datetime
DateTime
float
Double
int
Int32
nvarchar
String
uniqueidentifier
Guid
Tabulka 5.3.1: Převod databázových typu na C#.NET typy
Při generování EDM z databáze je programátor dotázán, jestli chce převést názvy tabulek do jednotných čísel. Tento krok zpřehledňuje práci s výslednými třídami. Porovnání použití při zachování množných čísel a převodu na jednotná je v příkladu 5.3.2. Z příkladu je viditelné zvýšení čitelnosti, když instance zastupující jeden záznam je typu Activity namísto Activities. S převodem na jednotné číslo: using (var context = new ClientDatabaseContainer()) { context.Activities.Add(new Activity()); Activity activity = context.Activities.First(); }
Při zachování množného čísla: using (var context = new ClientDatabaseContainer()) { context.Activities.Add(new Activities()); Activities activity = context.Activities.First(); }
Příklad 5.3.2: Porovnání výsledku převodu názvů tabulek na jednotná čísla
Na základě vygenerovaných tříd jsou vytvořeny tzv. Data Template Objects (DTO). Ty jsou přesnými kopiemi EDM tříd, umožňují však rozšíření o implementaci rozhraní a další rozšíření, využitelná již na úrovni knihovny. Název každé třídy odpovídá jejímu EMD ekvivalentu s přidaným „Data“ na konci.
37
Do těchto DTO tříd jsou převáděny objekty získané z databáze ve formě entit. EDM diagram lze vidět na obrázku 5.3.2. v porovnání s ER diagramem databáze (obrázek 5.3.1) lze vidět, že EDM je věrným obrazem.
Obrázek 5.3.2: EDM diagram
Mimo to lze na EDM diagramu vidět navigační vlastnosti, které jsou generované na základě vztahů. v důsledku pak každá entita má informaci o provázanosti s ostatními entitami a podstatně to usnadňuje navigaci. Programátor tak může od jedné entity přistupovat k entitě nebo setu entit s ní provázané přímo o což se stará EF. v porovnání s tím bychom pro dosažení stejného výsledku pomocí SQL museli provést dvoje volání pomocí SELECT, nebo sestavit jeden delší příkaz složený z vzájemně vnořených SELECT příkazů.
5.3.4 DatabaseWatch DatabaseWatch je třída, která se stará o databázi jako celek. Jejími cíli jsou:
Zajištění existence databáze
Zajištění kompatibility databáze
Verzování databáze
Zajištění číselníků 38
Základem třídy je její statický konstruktor, který načítá všechny changescripty a poslední možnou verzi databáze o tom, co jsou to changescripty a jak je realizováno verzování databáze pojednává část Verzování. EnsureDatabase je statickou bezparametrovou metodou bez návratové hodnoty. Jejím cílem je zajištění všech předchozích bodů. Pro tento účel využívá čtyři další statické metody. Průběh metody lze vidět na obrázku 5.3.3.
Obrázek 5.3.3: EnsureDatabase průběh
Nejprve se vytvoří objekt typu ClientDatabaseContainer pomocí bezparametrického konstruktoru. Ten si z konfiguračního souboru aplikace App.config načte connection
39
string (připojovací řetězec), který obsahuje veškeré informace o přístupu k databázi, jako je cesta k souboru, heslo nebo poskytovatel připojení. Následně, je-li databáze již vytvořena, pak se zkontroluje její kompatibilita s aktuální verzí aplikace. To je zjištěno pomocí statické metody EnsureCompatibility, která jako parametr přijímá objekt typu ClientDatabaseContainer. v případě nekompatibility je vyhozena výjimka. Pokud databáze neexistuje, pak je vytvořena. Po vytvoření je naplněna výchozími hodnotami
pomocí
statické
metody
FillDefaults,
které
je
objekt
typu
ClientDatabaseContainer předán jako parametr. Následně musí být do databáze zapsán záznam o aktuální verzi databáze – verzování bude popsáno dále. Nakonec se pro kontrolu provede aplikace poslední verze, která slouží pro odchytávání chyb při vydání nové verze databáze. Nakonec je databáze uložena pomocí bezparametrové metody SaveChanges, která je přístupná skrze objekt ClientDatabaseContainer. Po vyřešení existence databáze je vždy zavolána metoda EnsureVersion, které je jako parametr předložen objekt typu ClientDatabaseContainer. Kroky prováděné touto metodou budou popsány v následující části Verzování. Verzování Pro pochopení verzování je třeba nejprve vysvětlit pojem changescript. Changescript je v tomto případě soubor s příponou „sql“. Jak již přípona napovídá, jedná se o soubor, který obsahuje sled příkazů v jazyce SQL, které mají být provedeny. Tyto changescripty jsou uloženy v Assembly knihovny EasyWorklogLibrary jako EmbeddedResource. Jsou tedy součástí knihovny, která je publikována společně s novou verzí aplikace EasyWorklog. Pro changescripty je použit název ve formě pětimístného čísla shodného s verzí. Při zavolání statického konstruktoru DatabaseWatch jsou tedy, jak již bylo řečeno dříve, načteny všechny changescripty a uloženy do statického slovníku, jehož klíč je typu int a hodnota je typu string. Jako klíč je použita verze changescriptu získaná z jeho názvu a jako hodnota je uložen celý název, jakým je v Assembly reprezentován. Statická
metoda
EnsureVersion
pak
pracuje
s předaným
objektem
typu
ClientDatabaseContainer. Z dané databáze zjistí jaká je její verze. Pokud je nižší, než poslední verze uvedená v knihovně, pak jsou načteny chybějící changescripty a jeden po 40
druhém aplikovány formou transakcí. Transakce umožňují v případě chyby provést návrat před pokusem o provedení. Tím se vyhneme uvedení databáze do nekonzistentního stavu a případné ztrátě dat jejím poškozením. Verzováním skrze changescripty znamená, že jakákoliv změna databáze je provedena pomocí changescriptu, který je distribuován spolu s novou verzí aplikace. Tím pádem nemůže dojít k rozdílu mezi EDM a modelem již existující databáze, protože je vždy před použitím aktualizována stejnými příkazy. Navíc mohou changescripty fungovat jako historie změn, které byly v databázi provedeny.
5.4 EasyWorklog EasyWorklog je projekt samotné. Aplikace EasyWorklog je WPF aplikací, která je psaná dle MVVM návrhového vzoru. Aplikaci tedy rozeberu na pět hlavních částí.
Datové třídy
Obslužné třídy
Vlastní ovládací prvky
Uživatelské prostředí
Styly
Jazyková lokalizace
Export do xlsx
Další funkce
5.4.1 Datové třídy Datové třídy jsou identické s třídami, které se nachází v EasyWorklogLibrary.Data. Pro tyto
třídy
jsem
zvolil
jména
zakončená
slovem
„Object“,
jelikož
Všechny třídy ve jmenném
z EasyWorklogLibrary.PropertyObjectBase.
dědí
prostoru
EasyWorklog.Data implementují tato rozhraní:
IDataErrorInfo
–
rozhraní
se
nachází
ve jmenném
prostoru
System.ComponentModel. Toto rozhraní poskytuje jednoduchý centralizovaný způsob validace dat. Mimo jiné je kompatibilní s WPF. 41
IDTOBased – toto rozhraní ukládá definici metod GetDTO a LoadDTO, které lze využít k získání objektu typu T nebo načtení dat z objektu typu T. Pojmenování počítá s DTO třídami, ale za T lze dosadit jakýkoliv typ, který je třídou.
IHaveId – toto rozhraní ukládá definici vlastnosti Id, která je typu T.
ICopyFrom – objekty s tímto rozhraním mají metodu CopyFrom pro zpracování dat z objektu typu T.
ILockable – tuto metodu implementují jen některé třídy. Ukládá definici vlastnosti Locked, která značí, jestli je objekt zamknutý a metodu Lock, která objekt zamyká.
5.4.2 Obslužné třídy Tyto třídy jsou zdrojem informací pro ViewModel třídy. Jedná se o soběstačné třídy, které zajišťují určitou funkcionalitu. Mezi ně tedy patří:
AppDirectories
Extensions
CollisionsMaster
DataMaster
NotificationsMaster
RestrictionsMaster
Settings
Kromě AppDirectories, Extensions a Settings, obsahují třídy ve svém názvu „Master“. Záměrem je jistá konzistence označení těchto obslužných tříd, kterým je vyhrazena určitá doména. Stejně tak jsou všechny třídy, vyjma AppDirectories a Extensions, registrovány v IoC kontejneru jako singleton třídy. AppDirectories Tato statická třída poskytuje cestu k datům aplikace. Jmenovitě se jedná o cestu ke složce, která obsahuje data uživatele, dále pak cesta k databázi, složce s výjimkami, složce se zálohami databáze a souboru s nastavením aplikace. K dispozici dává dvě metody. Metoda EnsureDirectories kontroluje existenci složek, které aplikace využívá. EnsureDatabase pak s využitím DatabaseWatch, se kterou jsme se setkali v EasyWorklogLibrary, zajišťuje přítomnost a funkčnost databáze.
42
Extensions Tato statická třída plní stejnou funkci jako ExtensionsLib z EasyWorklogLibrary, což je rozšíření funkcionality existujících tříd. Rozšiřuje pouze třídu ObservableCollection a to třemi metodami. První metodou je Synchronize, která je viditelná v příkladu 5.4.1. v této metodě dochází k synchronizaci staré kolekce (kolekce, na které je tato metoda volána) přístupnou pod jménem
„oldCollection“
s kolekcí
novou,
která
je
předána
jako
parametr
„newCollection“. v deklaraci je vidět omezení na typ T, který může být touto metodou synchronizován. Podmínkou je, že typ T implementuje rozhraní IHaveId a ICopyFrom. public static void Synchronize(this ObservableCollection oldCollection, IEnumerable newCollection) where T:IHaveId, ICopyFrom { T edit; foreach(var item in newCollection.Where( w => oldCollection.Any(any => any.Id == w.Id))) { edit = oldCollection.First(f => f.Id == item.Id); edit.CopyFrom(item); if (edit is IDetectChanges) ((IDetectChanges)edit).HasChanges = false; } foreach(var delete in oldCollection.Where( w => !newCollection.Any(any => any.Id == w.Id)).ToArray()) { App.Current.Dispatcher.Invoke(() => { oldCollection.Remove(delete); } ); } int i = 0; foreach(var add in newCollection.Where(w => !oldCollection.Any( any => any.Id == w.Id)).ToArray()) { App.Current.Dispatcher.Invoke(() => { oldCollection.Add(add); }); if (add is IDetectChanges) ((IDetectChanges)add).HasChanges = false; i++; } }
Příklad 5.4.1: Metoda Synchronize
Další metodou je RegisterAndApplyCollectionChanged, která registruje metodu předanou v parametru „action“ k události CollectionChanged volané kolekce a zároveň, pokud je definována, provede s každým objektem v kolekci metodu „addAction“. 43
Stejným způsobem funguje i metoda UnRegisterAndApplyCollectionChanged s tím rozdílem, že po odhlášení metody „action“ od události CollectionChanged se s každým objektem v kolekci zavolá metoda „removeAction“, pokud je definována. CollisionsMaster Instance této třídy poskytuje zjištění a poskytnutí kolizí. Za tímto účelem je k dispozici metoda CheckCollisions a vlastnost Collisions, která je typu ObservableCollection. Ke své práci vyžaduje vždy čerstvá data – tu by bylo možné získat skrze předaný parametr, nebo mnou zvolenou metodou centrální třídy, která je všem ostatním přístupná. Jedná se o třídu DataMaster, která bude popsána dále. Mimo to je třeba mít k dispozici nastavení, kde se nachází informace nezbytná pro funkci CheckCollisions o intervalu, v kterém má kolize vyhledávat. Metoda CheckCollisions přijímá jako parametr objekt typu DateTime, který nese informaci o tom, jaký měsíc má být zkontrolován. Parametr typu Guid? je pak místem pro Id profilu, o který se jedná. Pokud není druhý nebo oba nastaven, pak jsou použity defaultní hodnoty. To má za následek, že jsou kontrolovány všechny činnosti všech projektů pro současný měsíc. Výsledkem této metody je naplnění kolekce Collisions. Zde výsledky zůstanou, dokud není metoda CheckCollisions zavolána znova. DataMaster Jedná se o esenciální třídu. Je mezivrstvou mezi ViewModel a komunikací s databází. Tato mezivrstva se stará o asynchronní aktualizaci dat načtených v aplikaci s daty v databázi. Také poskytuje DTO objekty převedené do podoby sledovatelných kolekcí objektů děděných z PropertyObjectBase, které jsou potřebné pro správné zobrazování v jednotlivých View. Také skrze ní probíhá asynchronní ukládání dat do databáze. Jednotlivé aktualizace jsou přidávány do fronty, která je následně zpracovávána metodou ProcessUpdates, která je zobrazena v příkladu 5.4.2. Z příkladu lze vyčíst, jakým způsobem je asynchronní aktualizace zajištěna. v případě, že neprobíhá aktualizace, je při zavolání této metody založena nová úloha, jinak metoda okamžitě končí. Samotná úloha pak probíhá tak dlouho, dokud nezpracuje celou frontu. Jelikož se jedná o asynchronní zpracování, může dojít ke změně fronty a odebírání 44
i přidávání do fronty tak musí být pod jedním zámkem. Zajímavými metodami, které zde lze vidět jsou IncrementSyncCount, DecrementSyncCount a IncrementOpsCounter. Zatím co první dvě metody se starají o aktualizaci zobrazení, jestli probíhají nějaké operace, tak metoda třetí inkrementuje počítadlo proběhlých operací. Když přesáhne určitou hodnotu, je vynulováno a provede se záloha databáze. public void ProcessUpdates() { lock(processingTaskLock) { if(processingTask == null || processingTask.Status != TaskStatus.Running) { lock (updateTasksLock) { processingTask = Task.Factory.StartNew(delegate { try { IncrementSyncCount(); while (updateTasks.Count > 0) { Task task; lock (updateTasksLock) task = updateTasks.Dequeue(); task.Start(); task.Wait(); } } finally { DecrementSyncCount(); IncrementOpsCounter(); } }); } } } }
Příklad 5.4.2: Zpracování nových hodnot
NotificationsMaster Tato jednoduchá třída dává k dispozici centralizovaný způsob upozornění uživatele. Je možné ji dále rozšířit o evidenci těchto upozornění, případně přidat nové možnosti. K zobrazení notifikací využívá jeden DialogWindowView a DialogWindowViewModel, kterému nastaví požadované texty před jeho zobrazením. Jelikož jsou zobrazující TextBlock elementy navázány na dané vlastnosti, bylo by možné text měnit i dodatečně. 45
RestrictionsMaster Instance této třídy zpřístupňuje, skrze jednu přetíženou metodu, kontrolu předaných činností na kolizi s omezeními. Výsledkem je dané omezení, které bylo porušeno jako první. Settings Instance této třídy dává k dispozici vlastnosti, které drží jednotlivé hodnoty nastavení. Instance této třídy je serializována do formátu JSON (JavaScript Object Notation) a uložena ve složce s daty aplikace. Hlavními ukládanými hodnotami jsou:
Jazyk – jazyk aplikace.
Barevné téma – barevné schéma aplikace.
Spuštění po startu Windows.
Zobrazení dotazu na ukončení aplikace.
Ignorace kolizí – umožní uložit činnost navzdory kolizím.
Ignorace limitů – umožní uložit činnost navzdory překročeným limitům.
5.4.3 Vlastní ovládací prvky Vlastní ovládací prvky se nacházejí ve jmenném prostoru EasyWorklog.Controls. Tyto ovládací prvky dědí ze třídy, která je nejbližší jejich zamýšlené funkci. Nejčastěji se však setkáme s UserControl, která je základním kontejnerem pro vlastní ovládací prvky. Calendar Příkladem vlastních ovládacích prvků, které jsou generovány jako UserControl je například Calendar. Calendar se stará o zobrazení dat, které implementují rozhraní ICalendarObject, ve formě kalendáře, nebo tabulky. Režim kalendáře může být vidět na obrázku 5.4.1.
46
Obrázek 5.4.1: Režim kalendáře
Na obrázku 5.4.1 jsou vyznačeny 3 oblasti. 1. Ovládací prvky pro přesun mezi měsíci, které jsou společné pro oba režimy. Změna měsíce je možná 3 způsoby: a. Kliknutím na šipku vpravo nebo vlevo. b. Posun kurzoru nad datum a rotací kolečka. c. Klepnutím na číslo měsíce nebo roku a přepsáním hodnoty. 2. Pro rychlý návrat na aktuální měsíc se při přechodu na jakýkoliv jiný měsíc zobrazí tento text. Po kliknutí se uživatel vrátí na náhled objektu aktuálního měsíce. 3. Objekt reprezentující den. Jeho vzhled je dán objektem typu DataTemplate, který je uložen v DP s názvem ItemTemplateProperty. Zbytek elementů viditelných na obrázku 5.4.1 je generován automaticky. Režim tabulky je pak vidět na obrázku 5.4.2. Na něm jsou vyznačeny čtyři oblasti. 1. Ovládací prvky pro přesun mezi měsíci. 2. Výběrový prvek, který poskytuje možnost změny množství položek zobrazených na jedné stránce. 3. Řádek s názvy sloupců je předán jako objekt typu object pomocí DP s názvem HeaderRowProperty.
47
4. Šablona jednotlivých položek tabulky je pak uložena jako objekt typu DataTemplate v DP s názvem TableItemTemplateProperty.
Obrázek 5.4.2: Režim tabulky
Window2013 Proti ovládacímu prvku Calendar, který je definován jako WPF UserControl, je Window2013 pouze třídou, která dědí z třídy Window. v této třídě je definována funkce a obsluha okna. Samotný vzhled okna je pak definován pouze jako styl. To nám zaručí, že vzhled okna bude vždy takový, jak je definovaný ve stylu. Okno je totiž při spuštění aplikace vykresleno se základním vzhledem, tudíž má preferenci nad námi definovaným. To však neplatí o stylu, který je aplikován až po vykreslení okna. Samotný vzhled okna by mohl být vyřešen pouhým stylem. Jelikož je však při kompletním přepsání okna nutné upravit jeho chování, je deklarace této třídy s dotyčnými funkcemi nezbytná. Mezi možnosti, kvůli kterým jsem psal vlastní okno, patří např. kompletně vlastní pás s titulkem a tlačítky pro zavření, přechod okrajů okna do ztracena a další.
48
5.4.4 Uživatelské prostředí Uživatelské prostředí je tvořené jednotlivými View, kde ke každému existuje jeho ViewModel. Jelikož je zde využit Caliburn.Micro, který se stará o propojení View a ViewModel, nesetkáme se u těchto náhledů s přímým propojením View s ViewModel. Kdybych chtěl docílit stejného výsledku, pak bych postupoval následovně: 1. Vytvoření objektu View třídy a objektu jí náležící ViewModel třídy. 2. Nastavení ViewModel objektu jako DataContext View objektu. 3. Zobrazení View objektu. Caliburn však umožňuje mimo jiné i snadné navázání na metody, které se nacházejí ve ViewModel objektu. Docílit stejného výsledku by bylo možné například pomocí delegátů. To by však bylo z hlediska kódu mnohem pracnější a jakékoliv zpětné úpravy časově náročnější. Caliburn vyžaduje, aby ViewModel třídy byly uloženy tak, aby při odstranění veškerých výskytů „Model“ ve jmenném prostoru včetně názvu byla výsledkem cesta k hledané View třídě. Např. EasyWorklog.ViewModels.RootViewModel je redukováno na EasyWorklog.Views.RootView. Tím je tedy nutné dodržet jak pojmenování ViewModel tříd, tak jejich umístění, které v podstatě kopíruje své protějšky. Hlavní okno aplikace Na obrázku 5.4.3 je vidět hlavní okno aplikace. Element hlavního okna je složen dle MVVM z RootView, které udává vzhled a rozložení elementů a RootViewModel, který zpřístupňuje zobrazovaná data a stará se o obsluhu stavu svého View. Stavem se rozumí zobrazení elementů, aktuálně zobrazených dat a další.
49
Obrázek 5.4.3: Hlavní okno aplikace
Zvýrazněné části viditelné na obrázku 5.4.3 jsou: 1. Probíhající činnosti – zobrazuje počet neukončených činností. Po kliknutí je zobrazen seznam daných činností a kliknutím na ně je možné přejít k jejich editaci. 2. Počet kolizí – zobrazuje počet kolizí v aktuálním měsíci plus mínus jeden měsíc. Kliknutím se přejde do náhledu kolizí, kde jsou kolize systematicky zobrazené pro jednoduchou orientaci a rychlé řešení. 3. Hlavní navigační lišta – vertikální navigační lišta, která kontroluje obsah okna. Umožňuje přechod mezi hlavními náhledy. 4. Kontrolní lišta – vertikální lišta s ovládacími prvky, které se vztahují k právě zobrazenému obsahu hlavního okna. 5. Ikona aplikace. 6. Název aplikace. 7. Základní ovládací prvky stavu okna aplikace – tlačítka pro minimalizaci, zmenšení/maximalizaci okna a ukončení aplikace. 8. Aktivní obsah. Na obrázku je vidět aplikace ve výchozím stavu, kdy je zobrazen kalendářní přehled činností všech projektů aktuálního měsíce. Toho je docíleno tak, že při načtení okna je
50
spuštěna inicializace dat z databáze a následně je zavolána metoda pro zobrazení náhledu všech činností. Při