Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I mark a control as 'Private' in WPF?

Tags:

c#

private

wpf

With WinForms programs I've become accustomed to marking the Modifiers property of a control as 'Private' to prevent external classes and whatever else have you from being able to see and mess with them.

Being still very green with WPF, I see no obvious equivalent in WPF that allows me to make it so external classes cannot see a control I drop onto a form or another user control or what not. I did notice something of x:FieldModifier = "Private" but I get the error "x:FieldModifier = "Private" is not valid for the language C#".

How do I mark a control as Private so it cannot be viewed or accessed by external class objects?

like image 210
Will Avatar asked Apr 08 '15 21:04

Will


People also ask

How do I create a control in WPF?

This topic discusses how controls (both those that do inherit from the Control class and those that do not) are commonly used in WPF. You can add a control to an application by using either XAML. All controls can be created similarly. The following example creates the same application in code.

Why should I use WPF controls?

Because the controls can display WPF visual elements and arbitrary data, there is less need to create a new control or to modify an existing control to support a complex visualization. For more information about the content model for Button and other content models in WPF, see WPF Content Model. Styles.

What is a controltemplate in WPF?

Classes that inherit from the Control class contain a ControlTemplate, which allows the consumer of a control to radically change the control's appearance without having to create a new subclass. This topic discusses how controls (both those that do inherit from the Control class and those that do not) are commonly used in WPF.

What is deriving from control class in WPF?

Deriving from Control Deriving from the Control class is the model used by most of the existing WPF controls. When you create a control that inherits from the Control class, you define its appearance by using templates. By doing so, you separate the operational logic from the visual representation.


1 Answers

TL;DR

Most of the time you don't need to worry about this in WPF. However:

  • If you name a XAML element using the x:Name attribute, then you can use the x:FieldModifier attribute to control the visibility of the auto-generated field representing that element. This attribute value is language- and case-specific.
  • If you don't name a XAML element, then don't bother using the x:FieldModifier attribute.

Read on for a more detailed explanation.


Explicit naming and generated fields

If you create a new WPF application project in Visual Studio, it will create a MainWindow class, the XAML for which looks something like this:

<Window x:Class="StackOverflow.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <Grid>

    </Grid>
</Window>

If you look at the code-behind class for this window, it will look like this:

// Several using statements...

namespace StackOverflow
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

Note the use of the partial keyword to denote this as a partial class. If you navigate to the project's obj\Debug folder using Windows Explorer, you will find a file called MainWindow.g.cs: it is this file that contains the code generated by the IDE from your XAML (it is basically the equivalent of the *.Designer.cs file from WinForms).

Your window has a Grid on it, but note that it is not surfaced directly anywhere in the code for MainWindow. Now edit your XAML to give the Grid a name:

<Grid x:Name="_myGrid">

Compile the application, and open the MainWindow.g.cs file again. You will see that the following line has been added:

internal System.Windows.Controls.Grid _myGrid;

Setting the x:Name property of the element in the XAML has caused the code generator to add a field with that name. The field is marked as internal which means it is accessible to all types in your project, but not to any other projects that reference your project.

So basically, if you do not explicitly name an element in the XAML using the x:Name attribute, the code generator will not create a named field for the element in the code-behind class, and your element will effectively be private (this means that the class itself cannot access the element directly either).


Nameless UI elements can still be accessed from code (if you have an instance)

An element without a name can still be accessed via code, by "walking" the visual tree of a Window instance. For example, because the window's content is set to a single Grid element, you can access that grid through code like so:

Grid grid = (Grid) this.Content;

this here refers to the MainWindow class instance.

WinForms has exactly the same "problem" as WPF in this regard: even controls that are not explicitly named can still be accessed through code. Imagine a WinForms Form with a single Button control on it. You can access that button like so:

Button button = (Button) this.Controls[0];

The fact that the button had a default Modifiers value of "Private" did not stop the code from being able to access it.


The FieldModifier attribute controls generated field visibility

Coming back to WPF, particularly if you're using the Model-View-ViewModel (MVVM) pattern, you will rarely need to explicitly name your elements in the XAML, hence the default behaviour will be fine. However, if you do find that you need to name your XAML elements, and you wish to "hide" these elements, then you can use the x:FieldModifier attribute to set the visibility of an element to private instead of the default internal. The value used for the attribute is language-dependent and case-sensitive, eg. for C#:

<Grid x:Name="_myGrid" x:FieldModifier="private">
like image 142
Steven Rands Avatar answered Oct 21 '22 03:10

Steven Rands