Atribut x:Name
v XAMLu vytváří pro elementy členské položky třídy, které lze použít pro přístup k ovladacím prvkům z kódu. Narozdíl od WPF však v UWP jsou tyto položky třídy definovány jako private, což znamená, že k nim je možné přistupovat pouze z třídy samotné. Pokud vezmeme v potaz, že z hlediska architektury by to byl špatný nápad, je možné toto chování změnit?
Výchozí chování
Definujme v XAMLu jednoduchý TextBlock
.
<TextBlock x:Name="InaccessibleTextBlock" />
Co se nyní stane, pokud vytvoříme novou třídu, která bude chtít změnit na jí předané stránce text tohoto ovladacího prvku?
public static class OutsideAccess { public static void ChangeTexts(MainPage page) { page.InaccessibleTextBlock.Text = "Accessed"; //does not work! } }
Aplikaci takto nelze zkompilovat, protože položka není přístupná kvůli její viditelnosti. Otevřme automaticky generovaný soubor MainPage.g.i.cs (ve složce obj), abychom se podívali, k čemu skutečně dochází:
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks"," 14.0.0.0")] private global::Windows.UI.Xaml.Controls.TextBlock InaccessibleTextBlock;
Vidíme, že položka je deklarována jako private.
Direktiva x:FieldModifier
Pro změnu výchozího chování XAML generátoru kódu můžete použít direktivu x:FieldModifier
. Ta vám umožňuje specifikovat přesně který modifikátor přístupu by položka měla mít.
<TextBlock x:FieldModifier="public" x:Name="AccessibleTextBlock" />
Nyní již je snadno možné přistoupit k položce i z jiné třídy:
public static class OutsideAccess { public static void ChangeTexts(MainPage page) { page.AccessibleTextBlock.Text = "Accessed"; } }
Kromě voleb public
a private
můžete hodnotu direktivy nastavit i jako internal
nebo protected
. Výsledek naší snahy můžeme ověřit i ve vygenerovaném zdrojovém kódu:
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks"," 14.0.0.0")] public global::Windows.UI.Xaml.Controls.TextBlock AccessibleTextBlock;
WPF
Pokud přemítate, jaké je výchozí chování ve WPF, odpověď je nasnadě! Konvence WPF nastavuje všechny pojmenované položky jako internal
:
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] internal System.Windows.Controls.TextBlock InaccessibleTextBlock;
I zde však můžete použít direktivu x:FieldModifier
pro úpravu viditelnosti stejně jako v UWP.
Zdrojový kód
Ukázkový zdrojový kód k tomuto článku najdete na mém GitHubu.
Shrnutí
x:FieldModifier
je zajímavá a nepříliš známá direktiva XAMLu. Přesto by její použití mělo být spíše výjimečné, protože členské proměnné viditelnosti jiné než private
nejsou nikdy dobrým nápadem. O to překvapivější je, že v případě WPF byla jako výchozí zvolena viditelnost internal
.