The x:Name attribute in XAML creates named fields that you can use to access the controls from the code-behind. However, as opposed to WPF, in UWP these fields are private which means you can access them from the code-behind only, not from other classes. While noting it is a good idea from architectural standpoint, is it possible to change this behavior?
Normal behavior
Let's define a simple TextBlock
control in XAML.
<TextBlock x:Name="InaccessibleTextBlock" />
Now, what happens if we create a new class that takes the page as parameter of one of the methods and tries to access the TextBlock
?
public static class OutsideAccess { public static void ChangeTexts(MainPage page) { page.InaccessibleTextBlock.Text = "Accessed"; //does not work! } }
The app will not compile, because the field is inaccessible due to its protection level. To see what actually happens behind the scenes, let's open the auto-generated MainPage.g.i.cs file which can be found in the obj folder. We can find the following field there:
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks"," 14.0.0.0")] private global::Windows.UI.Xaml.Controls.TextBlock InaccessibleTextBlock;
Clearly, the field is defined as private.
x:FieldModifier directive
To change the code generation behavior, you can use the x:FieldModifier
directive. This allows you to specify excatly which access modifier should be field have.
<TextBlock x:FieldModifier="public" x:Name="AccessibleTextBlock" />
Now, accessing the field from the outside works as a charm:
public static class OutsideAccess { public static void ChangeTexts(MainPage page) { page.AccessibleTextBlock.Text = "Accessed"; } }
Note that you are not limited to public
and private
only, and you can also set the field to be internal
or protected
. We can confirm the change of visiblity was reflected in the generated source code:
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks"," 14.0.0.0")] public global::Windows.UI.Xaml.Controls.TextBlock AccessibleTextBlock;
WPF
If you wonder, what is the default behavior in WPF, wonder no more! WPF's convention is to set all named fields as internal
by default:
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] internal System.Windows.Controls.TextBlock InaccessibleTextBlock;
You can use the x:FieldModifier
directive to modify the visibility the same way as in UWP.
Source code
Example source code for this article is available here on my GitHub.
Summary
The x:FieldModifier
is an interesting and less known directive of XAML. However, we should use it with caution as exposing fields as anything else than private is never a good idea. It is then quite surprising that in WPF internal
was chosen as the default.