Controls and Content

Earlier in this chapter, a control was defined as an element that is intended for user input. All XAML elements can respond to mouse and keyboard events, but elements such as the Grid do not, by default, do anything with those events. Controls possess functionality to process events and respond to them in some way.

The base Control class implements a lot of functionality needed by all controls, including:

  • Font properties for sizing and formatting of text
  • Properties for a background, foreground, and border
  • The TabIndex property to control the tab order
  • The capability to use a template to radically alter the appearance of a control

Most developers will have no issues in using these properties, so detailed descriptions are not necessary. This chapter does include a section on Brushes, which is relevant for setting Foreground and Background properties. Also, a section on control templates is included toward the end of the chapter to describe how to alter the fundamental appearance of a control.

Content Controls

Some controls in XAML descend from a base class named ContentControl, and have a property named Content. It is of type Object. You can set the Content property to any .NET object, and XAML will attempt to render it.

The Content property can be set explicitly, or by placing something between the tags of a ContentControl. Both of these are shown in this XAML example:

<Button Content="Save" />
<Button>
    Cancel
</Button>

These two ways of expressing a Button are equivalent. In either case, the Content property is set to a string.

Even though the Content property can be set to any object, from the standpoint of rendering content, objects fall into only two categories: objects that descend from the FrameworkElement class and objects that don't.

For general objects that do not descend from FrameworkElement, their rendering is simple. XAML calls the ToString method of the object, and uses the result as string-based content. XAML automatically creates a simple, lightweight text container called a TextBlock to hold and render the string.

That's the type of rendering used in all of the Button examples shown in the chapter up to this point. Since String is just another .NET type, XAML can call the ToString method (which just returns the string!) and places that in a XAML TextBlock created for the purpose.

For objects that do descend from UIElement, XAML already knows how to render them. They all have rendering behavior built in.

Implications of the Content Model

The concept of Content for controls is a game changer in terms of designing user interfaces. In older technologies, what you could place in controls such as buttons and tooltips was very restricted. In XAML, it's very open. You can set the Content property of Button to a Grid, for example, and then put whatever you like inside the Grid.

For example, if you need to put both an Image and a string in a XAML button, all you need do is construct appropriate content (code file: ButtonWithContent.xaml):

<Button Margin="5">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Image MaxHeight="60"
            Source="http://billyhollis.com/SkewedBooks.png" />
        <TextBlock Grid.Column="1" TextWrapping="Wrap"
                   Margin="3" Text="Order Books" />
    </Grid>
</Button>

This would yield a Button with the interior rendered exactly the way you specified. Figure 12.6 shows this XAML rendered in both WPF and Windows 8. The Button on the left is rendered in Windows 8 XAML, and the Button on the right is rendered in WPF on Windows 7, both using exactly the same XAML.

Figure 12.6 A Button with its interior determined by content featuring an Image and some text inside a Grid panel

12.6

Notice that you have complete control over how the image and text are arranged. In older technologies, some Button controls had minimal capability to display images and text, but control was always limited to a few choices.

The difference in XAML is based on the composition model. In older technologies, a Button control was totally responsible for its own internal layout. In essence, the Button had a layout engine built into it. It wasn't really practical to make that layout engine very flexible.

In XAML, the Button does not have any layout capability built in. It delegates layout to other XAML elements that specialize in layout. That means the entire spectrum of layout flexibility from the panels and related elements in XAML can be used inside a Button or other ContentControl. A Button can look like anything you like. Such capabilities as playing video inside a Button are possible and easy to construct (though you probably will not need particular capability in a typical business application).

Another example that illustrates the implications of the Content concept is XAML is the ScrollViewer. This element is responsible for scrolling on all three XAML platforms. ScrollViewer is a ContentControl, with the ability to scroll its content. That means you can make anything scrollable by placing it as content inside a ScrollViewer.

You can change our earlier example of XAML to allow scrolling of the StackPanel and its children very simply (code file: ScrollingStackPanel.xaml):

<UserControl x:Class="SampleUC"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300" >
    <Border BorderThickness="4" BorderBrush="Blue">
        <ScrollViewer>
            <StackPanel>
                <Button Margin="5">I'm a button</Button>
                <Image Margin="5" 
                Source="http://billyhollis.com/TextureWavy.jpg" 
                 />
                <TextBox Margin="5">Text for editing</TextBox>
            </StackPanel>
        </ScrollViewer>
    </Border>
</UserControl>

Brushes

Controls and other elements have properties such as Foreground, Background, Fill, Stroke, and BorderBrush to control how the elements are rendered. These properties are all of type Brush. In earlier technologies, you might expect properties like these to be of type Color, but the Brush type is more general and adds flexibility.

Expressing Colors in XAML

There are colors in XAML, of course. One type of Brush is a SolidColorBrush, and a Color is used to specify the solid color to be used.

Colors can be expressed in XAML in several ways. Each XAML platform has a set of named colors, accessible in code through the Colors class. The list is longer in some XAML platforms than others, but every XAML platform has the common colors you would expect, such as Red, Blue, Yellow, and so on.

Using a named color, the XAML for defining a background of solid green in a Border element looks like this:

<Border Background="Green"></Border>

The is parsed by the XAML engine to mean “create a SolidColorBrush using the named color Green and assign it to the Background of the Border.”

Colors can also be specified by HTML-like RGB values. The Border could have a grayish-cyan color set with this XAML:

<Border Background="#20A79E"></Border>

However, even though the XAML parser understands such colors, the visual designers will never insert RGB color values this way. Instead, the designers will insert colors with 4 hex pairs instead of 3, like this:

<Border Background="#FF20A79E"></Border>

The extra hex pair is inserted before the hex pairs for the red, green, and blue channels. That beginning hex pair (FF in the previous XAML) specifies the alpha channel, which controls the translucency of the color. Translucency ranges from FF (fully opaque) to 00 (fully transparent).

Layering Translucent Elements

In addition to getting translucency via the alpha channel, elements have an Opacity property. It ranges from 1 (full opaque) to 0 (fully transparent). It is of type Double, so it can take very fine grained values in between those two.

If elements are layered, and have translucent colors and/or translucency from their Opacity setting, the rendering engine will resolve all the layers for each pixel it paints. You may wish to experiment with translucent colors and the Opacity property to see some of the effects you can produce.

LinearGradientBrush and RadialGradientBrush

Because Foreground, Background, etc. are of type Brush, they can accept any value that is descended from that base type. Besides SolidColorBrush, there is one other brush type that is available for all three XAML platforms: LinearGradientBrush. Each individual XAML platform then has additional brushes. WPF has RadialGradientBrush, ImageBrush, and VisualBrush, Silverlight has RadialGradientBrush, ImageBrush, and VideoBrush, and Windows 8 XAML has TileBrush.

LinearGradientBrush can accept more than one color. It has a collection of GradientStop objects, and each GradientStop has a color. LinearGradientBrush then blends colors in a linear interpolation during rendering.

You don't really need to know the syntax of LinearGradientBrush in detail at this point. The visual designers do a good job of letting you create a LinearGradientBrush. The following is a typical LinearGradientBrush in XAML. Figure 12.7 shows the result of using it to fill a Rectangle.

Figure 12.7 A Rectangle filled with a LinearGradientBrush that is Black in the upper left corner and White in the lower right

12.7
<LinearGradientBrush EndPoint="1,1" StartPoint="0,0">
     <GradientStop Color="Black" Offset="0" />
     <GradientStop Color="White" Offset="1" />
</LinearGradientBrush>

The StartPoint and EndPoint properties of the LinearGradientBrush are relative to the element's bounding box. Thus, a StartPoint of “0,0” is the upper left corner of the element, and an EndPoint of “1,1” is the lower right corner. Any fractional values can be used for these properties, including values that get outside the bounding box.

The gradient stops are then positioned along a line drawn from the StartPoint to the EndPoint. The Offset property of the GradientStop determines its position along that line. Offset of “0” means the StartPoint, and an Offset of “1” means the EndPoint. Offset values may be anywhere in between, and a single LinearGradientBrush may have any number of GradientStops with differing Offset properties.

Importance of Gradients

You might think gradient brushes are frivolous, but used judiciously, they can dramatically improve the look of your application. Instead of the monochrome battleship gray that you might have used in the past, gradients can impart a natural feel to an application. After all, the real world does not contain much monochrome. Users are primed to consider monochrome as artificial, and gradients as natural.

The key is to create subtle gradients that are almost unnoticed by the user. Many developers start by using garish gradients that stand out. That is rarely a good use of that capability.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset