Systémy Windows Vista a Windows 7 již tady sice nějaký ten pátek jsou, ale jednak ze zkušenosti vím, že jsou i zákazníci (hlavně korporace), kteří např. k Windows 7 ještě nepřičichli. A dále rozhodně ne všichni mají aplikace pro tyto systémy správně připravené nebo nevyužívají některé vlastnosti, které např. vylepšují vzhled celé aplikace. Rád bych proto v několika článcích uvedl některé tipy / postřehy jak vylepšit uživatelské rozhraní (UI) desktopových (tlustých) aplikací, abyste uživatelům dopřáli to pravé User Experience a využili možnosti těchto zatím nejnovějších Windows systémů. (Než nám tyto desktopové aplikace nahradí metro a budeme mít úplně jiné starosti...) Technologicky se tyto články budou zabývat jak Windows Forms tak WPF.
Visual Style
Možná to ani nevíte, ale standardní Windows.Forms (WinForms) tlačítko není ve Windows Vista / 7 s Visual Style zobrazováno správně. Pokud najedete kurzorem myši na tlačítko, je jeho zobrazení změněno (Hover state), pokud ho pak zase myší opustíme vrací se do původního stavu. Podobně je to i se stavem kliknutí (Pressed), toto jiné zobrazení již známe od Winsow XP Visual Styles. Ve Windows Vista a Windows 7 ale tyto přechody nemají být rovnou, ale s postupnou animací přechodu (Fade Effect, Subtle animations) viz obr.
Toto se ale právě ve výchozím nastavení Windows.Forms tlačítka neprovádí samo a přechody jsou rovnou. Existuje k tomu ale jednoduchá oprava, stačí změnit v designeru hodnotu vlastnosti FlatStyle z výchozího Standard na System, nebo kódem:
this.Button.FlatStyle = FlatStyle.System;
Ještě je nutné zmínit, že obdobným chováním trpí dále controly Checkbox a RadioButton, u nich tuto změnu můžeme provést vždy, ale u tlačítka pouze tehdy, pokud v něm nezobrazujeme obrázek. (Obrázek se při FlatStyle = System standardně nezobrazuje).
(Pozn.: Podobně se tato změna FlatStyle na System kdysi prováděla ve FW 1.1 WinForms aplikací, kde se touto změnou a přidáním manifest souboru vynutilo zobrazení s Visual Styles pro Windows XP - podpora ve VS přišla až v FW 2.0)
Ve WPF aplikacích standartní styly pro tlačítko, Checkbox , RadioButton apod. obsahují vzhled, který kopíruje standardní vzhled těchto ovládacích prvků s Visual Styles ve Windows, pro daný theme – Aero (pro Win Vista / 7), Luna (s Metallic, Homestead podtypy), Royale (WinXP) nebo Classic (tyto čtyři natvrdo). Styl pro Aero v sobě pak obsahuje i animace přechodu mezi jednotlivými stavy kontrolu.
Může zde ale nastat jiný problém, pokud zkopírujeme základní styl např. v Blendu (abychom ho upravili), zkopíruje se styl pro aktuální theme vývojáře a ten je pak zobrazován vždy nezávisle na aktuálním theme při spuštění aplikace. Jinými slovy pokud např. máme aplikaci se dvěma tlačítky a prvnímu přiřadíme styl zkopírovaný v Blendu na Windows 7 (Aero theme), pak aplikaci spustíme na Windows XP, bude toto tlačítko zobrazeno tak jak jsou graficky zobrazena tlačítka ve Windows 7 (druhé tlačítko zůstane ve XP Visual Style). Pokud tedy chceme, aby i naše custom styly respektovali aktuální theme, řešením je definovat styly pro všechny themy, více o tom v článku Windows Themes in WPF.
Fonty
Pokud vytvoříme nový formulář ve WinForms, je jeho výchozí font (Control.DefaultFont) nastaven na Microsoft Sans Serif. Tento font ale standardní formuláře a dialogy ve Windows Vista / 7 ani XP nepoužívají. Aby naše aplikace byla vizuálně stejná jako jiné aplikace ve Windows, měly bychom používat font, který daný operační systém používá. Ve Windows XP je výchozí font Tahoma ve velikosti 11, v systémech Windows Vista a Windows 7 je to font Segoe UI velikosti 9.
Pozn.: Font Segoe UI není ve starších systémech jako Windows XP obsažen vůbec, pokud bychom ho nastavovali natvrdo (např. z VS designeru ve Windows 7), nebude aplikace ve Windows XP zobrazena správně. Font také není volně šiřitelný (podléhá commercial license) a tak ho nemůžeme distribuovat s aplikací.
K tomu, abychom v kódu získali tento správný font pro daný operační systém, můžeme využít vlastnost MessageBoxFont třídy System.Drawing.SystemFonts. (Nepoužívejte vlastnosti SystemFonts.DefaultFont nebo SystemFonts.DialogFont, ty vracejí font špatně, protože v sobě mají hardcoded font Tahoma). Takto vypadá kód, který opravuje nastavení fontu v konstruktoru formuláře.
public TestForm()
{
this.Font = System.Drawing.SystemFonts.MessageBoxFont
InitializeComponent();
UpdatePrimaryFont(SystemFonts.MessageBoxFont, this, true);
}
public static void UpdatePrimaryFont(System.Drawing.Font font, Control control, bool recurse)
{
if (!control.Font.Equals(font))
{
if (control.Font.Style == Control.DefaultFont.Style && control.Font.Size == Control.DefaultFont.Size) //Default settings
{
control.Font = font;
}
else
{
try
{
if (control.Font.Size == Control.DefaultFont.Size) //Default size
{
control.Font = new System.Drawing.Font(font, control.Font.Style);
}
else
{
control.Font = new System.Drawing.Font(font.FontFamily, control.Font.Size, control.Font.Style);
}
}
catch (Exception)
{
control.Font = font;
}
}
}
if (recurse && control.HasChildren)
{
foreach (Control childControl in control.Controls)
{
UpdatePrimaryFont(font, childControl, true);
}
}
}
Nejprve změníme výchozí font před tím, než se budou jednotlivé prvky v InitializeComponent sestavovat. Protože se ale v metodě InitializeComponent může vyskytovat změnění fontu (protože jsme ho např. v designeru nastavili na bold), je nutné poté ještě proběhnout všechny kontroly a případně font změnit (se zachováním stylu), k tomu slouží pomocná metoda UpdatePrimaryFont.
Pozn.: Tím že font změníme před InitializeComponent je většina controlu již vykreslena se správným fontem, a tím metoda UpdatePrimaryFont s nimi již nic neprovádí (nenastane tedy výkonnostní problém, že by se všechny kontroly formátovali na formulář dvakrát).
Koukněte na výsledek, první obrázek zobrazuje formulář s výchozím fontem bez úpravy, další zobrazují tentýž formulář se změnou fontů v systému Windows 7 a Windows XP.
Všimněte si ještě, že font Segoe UI je trochu větší než výchozí MS Sans Serif. Na to je potřeba myslet při tvorbě designu formulářů, v praxi se např. osvědčuje pro rozmisťování prvků používat Layout panely (TableLayoutPanel a FlowLayoutPanel). Na některých diskuzích k tomuto tématu jsou názory, že by se font MS Sans Serif neměl používat vůbec a měl by se zaměnit vždy. Já tuto myšlenku nesdílím, protože vzhledem k tomu, že nelze pouze jednoduše vyměnit font, ale je potřeba design k tomu připravit a odladit, tak to například u již existujících aplikací není možné jednoduše provést. Moje doporučení je provést tuto změnu aspoň v některých dialogových formulářích (např. v dialozích podobným MessageBoxům, které jsou systémem na tento font změněny automaticky).
Pozn.: Formulář na obrázku je z důsledku většího fontu zobrazen celý větší. je to tím, že má nastavenou vlastnost AutoScaleMode na hodnotu Font, k tomu se ještě dostaneme v druhé části.
Ve WPF aplikacích je výchozí font již správný, podle systému buď Segoe UI nebo Tahoma. (Stejně ale musíme myslet na rozdílnou velikost fontů, pokud tedy neděláme pouze Windows 7 aplikaci).
Uvedu zde ale jiný trik, jak vylepšit vzhled textů WPF aplikací. Někdy je font špatně vykreslen (menší velikosti fontu, nebo mě se to stávalo např. při zobrazení okna aplikace přes Remode Deskop v nižší paletě barev). Ve WPF 4.0 je nově vlastnost TextOptions.TextFormattingMode a její nastavení Display, které mění výchozí zobrazení fontů, její popis v MSDN je následující: ‘Indicates that the TextFormatter lays out text by using GDI-compatible font metrics’. Pro klasické Windows desktopové aplikace ve WPF doporučuji tuto hodnotu Display nastavit, buď v XAML:
TextOptions.TextFormattingMode="Display"
nebo v C# kódu:
SetValue(TextOptions.TextFormattingModeProperty, TextFormattingMode.Display);
Příště si povíme něco o podpoře High DPI v našich aplikacích.
Článek byl částečně inspirován tímto blog příspěvkem:
http://wyday.com/blog/2009/windows-vista-7-font-segoe-ui-in-windows-forms/