System.Windows.Media.Visual is a base class that is shared by all of the controls that we have seen so far in the WPF tutorial. Later in the tutorial we'll see many other controls that also inherit functionality from this class.
Visual adds methods and properties to those that it inherits from DispatcherObject and DependencyObject. It provides functionality that is specific to the rendering of WPF controls. Some of this is purely visual. For example, the class controls the application of transforms and visual effects to controls, allows controls to be made fully or partially transparent with a visual opacity, and determines the type of font rendering to use.
Some of the functionality added to controls by the Visual class controls user feedback. For example, the class determines the bounding boxes for controls and performs hit testing to determine whether a mouse input or touch gesture should apply. The class also allows interrogation of, and modification to, the visual tree. This permits controls to identify their ancestors and descendants in the tree and allows you to dynamically add new visual elements.
Most of the methods and properties of the Visual class are protected. They can be used directly from subclasses but creating such inheritance relationships is beyond the scope of this article. We will see the functionality provided by the protected members indirectly when we work with other WPF base classes in later articles.
Ancestors and Descendants
The Visual class has a few public methods that can be useful. Three such methods allow you to interrogate the structure of your user interface and the relationships between controls. The relationships are linked to the object trees, which were described in the XAML article.
Within the hierarchical tree of controls that make up a user interface, controls that are linked can be categorised as ancestors or descendants. An ancestor is a parent control and its child controls are its descendants. Imagine you have a Grid control that contains several Labels. The Grid is an ancestor of the labels and the labels are descendants of the Grid. Note that the Grid is only one ancestor of the labels. The relationship continues up the tree so every ancestor of the Grid is also an ancestor of the labels.
To demonstrate the methods that permit you to determine ancestors and descendants we need a sample project. Open Visual Studio and create a new WPF application project, using the name, "VisualDemo". Replace the XAML of the initial window with the following code:
<Grid ShowGridLines="True" Name="MainGrid">
<UniformGrid Name="UGrid" Grid.Column="1" Background="PapayaWhip">
<Grid Grid.Row="1" Background="PapayaWhip">
The XAML defines several events so switch to the code behind the window and add the following three placeholder methods:
private void IAO_Click(object sender, RoutedEventArgs e)
private void IDO_Click(object sender, RoutedEventArgs e)
private void CA_Click(object sender, RoutedEventArgs e)
The window includes a Grid named "MainGrid" that holds a StackPanel of buttons, a UniformGrid of labels and a second Grid. The inner grid holds a Viewbox, which contains a further label control. This gives a tree with several levels.
When rendered, the design of the user interface is as shown below:
The hierarchy of controls is illustrated below. The boxes include the types of controls, with the names shown in parentheses where a name has been specified. Each connecting line indicates a relationship between an ancestor and a descendant, with the ancestor appearing above the descendant in each case.
7 July 2013