Úprava viditelnosti pojmenovaných XAML elementů

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.

Buy me a coffeeBuy me a coffee

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.