Windows Presentation Foundation

Hello, WPF

WPF from Scratch
Navigation Applications
Content Model
Layout
Controls
Data Binding
Dependency Properties
Resources
Styles and Control Templates
Graphics
Application Deployment
Where Are We?

Layout

Introduction
Layout Basics
DockPanel
StackPanel
Grid
Canvas
Viewbox
Text Layout
Common Layout Properties
When Content Doesn't Fit
Custom Layout
Where Are We?

Controls

Introduction
What Are Controls?
Handling Input
Built-In Controls
Where Are We?

Data Binding

Introduction
Without Data Binding
Data Binding
Binding to List Data
Data Sources
Master-Detail Binding
Where Are We?

Styles and Control Templates

Introduction
Without Styles
Inline Styles
Named Styles
Element-Typed Styles
Data Templates and Styles
Triggers
Control Templates
Where Are We?

Resources

Introduction
Creating and Using Resources
Resources and Styles
Binary Resources
Global Applications
Where Are We?

Graphics

Introduction
Graphics Fundamentals
Shapes
Brushes and Pens
Transformations
Visual-Layer Programming
Video and 3-D
Where Are We?

Animation

Animation Fundamentals
Timelines
Storyboards
Key Frame Animations
Creating Animations Procedurally
Where Are We?

Custom Controls

Introduction
Custom Control Basics
Choosing a Base Class
Custom Functionality
Templates
Default Visuals
Where Are We?

ClickOnce Deployment

A Brief History of Windows Deployment
ClickOnce: Local Install
The Pieces of ClickOnce
Publish Properties
Deploying Updates
ClickOnce: Express Applications
Choosing Local Install versus Express
Signing ClickOnce Applications
Programming for ClickOnce
Security Considerations
Where Are We?

Visual-Layer Programming

7.5. Visual-Layer Programming

The shape elements can provide a convenient way to work with graphics. However, in some situations, adding elements representing a drawing to the UI tree may be more trouble than it's worth. Your data may be structured in such a way that it's easier to write code that simply performs a series of drawing operations based on the data, rather than constructing a tree of objects.

WPF provides a "visual layer" API as a lower-level alternative to shape elements. (In fact the shape elements are all implemented on top of this visual layer.) This API lets us write code that renders content on demand.

A visual is a visible object. A WPF application's appearance is formed by composing all of its visuals onto the screen. Since WPF builds on top of the visual layer, every element is a visualthe FrameworkElement base class derives indirectly from Visual. Programming at the visual layer simply involves creating a visual and writing code that tells WPF what we'd like to appear in that visual.


Even at this low level, WPF behaves very differently from Win32. The way in which graphics acceleration is managed means that your on-demand rendering code is called much less often than it would be in a classic Windows application.

7.5.1. Rendering On Demand

The key to custom on-demand rendering is the OnRender method. This method is called by WPF when it needs your component to generate its appearance. (This is how the built-in shape classes render themselves.)

The virtual OnRender method is defined by the OnDemandVisual class. Most elements derive from this indirectly via FrameworkElement, which adds core features such as layout and input handling.


Example 7-47 shows a custom element that overrides OnRender.

Example 7-47. A custom OnRender implementation
public class CustomRender : FrameworkElement
{
    protected override void OnRender(DrawingContext drawingContext)
    {
        Debug.WriteLine("OnRender");

        base.OnRender(drawingContext);

        drawingContext.DrawRectangle(Brushes.Red, null, new Rect(0, 0, 100, 50));

        FormattedText text = new FormattedText("Hello, world",
            CultureInfo.CurrentUICulture, FlowDirection.LeftToRightThenTopToBottom,
            new Typeface("Verdana"), 24, Brushes.Black);
        drawingContext.DrawText(text, new Point(3, 3));
    }

}

The OnRender method is passed a single parameter of type DrawingContext . This is the low-level drawing API in WPF. It provides a set of primitive drawing operations, which are listed in Table 7-4. Example 7-47 uses the DrawRectangle and DrawText methods.

Note that the DrawingContext uses the Brush and Pen classes to indicate how shapes should be filled and outlined, just like the higher-level shape objects we saw earlier. We can also pass in the same Geometry and Drawing objects we saw earlier in the chapter.

Table 7-4. DrawingContext drawing operations

Operation

Usage

DrawDrawing

Draws a Drawing object.

DrawEllipse

Draws an ellipse.

DrawGeometry

Draws any Geometry object.

DrawGlyphRun

Draws a series of glyphs (i.e., text elements) offering detailed control over typography.

DrawImage

Draws a bitmap image.

DrawLine

Draws a line (a single segment).

DrawRectangle

Draws a rectangle.

DrawRoundedRectangle

Draws a rectangle with rounded corners.

DrawText

Draws text.

DrawVideo

Draws a rectangular region that can display video.

PushTransform

Sets a transform that will be applied to all subsequent drawing operations until Pop is called; if a transform is already in place, the net effect will be the combination of all the transforms currently pushed.

PushClip

Sets a clip region that will be applied to all subsequent drawing operations until Pop is called; as with PushTransform, multiple active clip regions will combine.

PushOpacity

Sets a level of opacity that will be applied to all subsequent drawing operations until Pop is called; as with transforms and clips, multiple opacities are combined.

Pop

Removes the transform, clip region, or opacity added most recently by PushTransform, PushClip, or PushOpacity. If those methods have been called multiple times, calls to Pop remove their effects in reverse order. (The transforms, clip regions, and opacities behave like a stack.)


Because our custom element derives from FrameworkElement, it integrates naturally into any WPF application. Example 7-48 shows markup for a window that uses this custom elementwe can use it just like we'd use any custom element. This window is shown in Figure 7-56.

Example 7-48. Loading a custom visual into a window
<?Mapping XmlNamespace="controls" ClrNamespace="VisualRender" ?>
<Window x:Class="VisualRender.Window1"
    xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
    xmlns:cc="controls"
    Text="Visual Layer Rendering"
    >

    <Canvas>
        <cc:CustomRender Canvas.Top="10" Canvas.Left="10" x:Name="customRender" />
    </Canvas>
</Window>

Figure 7-56. Visual layer rendering in action


Notice that the OnRender function in Example 7-47 calls Debug.WriteLine . If the program is run inside the VS 2005 debugger, this will print a message to the Output window each time OnRender is called. This enables us to see how often WPF asks our custom visual to render itself. If you are used to how the standard on-demand painting in Win32 and Windows Forms works, you might expect to see this called regularly whenever the window is resized or partially obscured and uncovered. In fact it is called just once!

It turns out that on-demand rendering is not as similar to old-style Win32 rendering as you might think. WPF will call your OnRender function when it needs to know what content your visual displays, but the way graphics acceleration works in WPF means that this happens far less often than the equivalent repaints in Win32. WPF caches the rendering instructions. The extent and form of this caching is not documented, but it clearly occurs. Moreover, it is more subtle than simple bitmap-based caching. We can add this code to the host window in Example 7-48 (this would go in the code-behind file):

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        VisualOperations.SetTransform(customRender, new ScaleTransform(6, 6));
    }

The preceding snippet applies a transform to our element, scaling it up by a factor of 6. When clicking on the user interface, the custom visual expands as you would expect, and yet OnRender is not called. Moreover, the enlarged visual does not show any of the pixelation or blurring artifacts you would see with a simple bitmap scaleit continues to be sharp, as you can see in Figure 7-57.

Figure 7-57. Scaled custom rendering


This indicates that WPF is retaining scalable information about the contents of the visual. It is able to redraw our visual's onscreen appearance without bothering our OnRender method, even when the transformation has changed. This is in part due to the acceleration architecture, but also because transformation support is built into WPF at the most fundamental levels.

WPF's ability to redraw without calling OnRender allows the user interface to remain intact onscreen even if our application is busy. It also enables the animation system to work without much intervention from the applicationbecause all of the primitive drawing operations are retained, WPF can rebuild any part of the UI that it needs to even when individual elements change.

If the state of our object should change in a way that needs the appearance to be updated, we can call the InvalidateVisual method. This will cause WPF to call our OnRender method, allowing us to rebuild the appearance.

Note that when you override OnRender, you should typically also override the MeasureOverride and ArrangeOverride methods. Otherwise, WPF's layout system will have no idea how large your element is. The only reason we got away without doing this here is that we used the element on a Canvas, which doesn't care how large its children are. To work in other panels, it is essential to let the layout system know your size. Chapter 2 described the MeasureOverride and ArrangeOverride methods.


©2008 FAQ - WPF Labs - Discuss - Terms of Use - Privacy Policy - About WPF
- Interview Questions - Sharepoint Articles - Interview Questions Resource Library - All about LINQ - MS Knowledgebase Articles - Electronics and Hardware discussions