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?

Custom Layout

Custom Layout

Although WPF supplies a flexible set of layout elements, you might decide that none of them suits your requirements. Fortunately, the layout system is extensible, and it is fairly straightforward to implement your own custom panel. To write a panel, you need to understand how the layout system works.

Layout occurs in two phases: measure and arrange. Your custom panel will first be asked how much space it would like to havethat's the measure phase. The panel should measure each of its children to find out how much space they require and then decide how much space the panel needs in total.

Of course, you can't always get what you want. If your panel's measure phase decides it needs an area twice the size of the screen, it won't get that in practice. (Unless its parent happens to be a ScrollViewer .) Moreover, even when there is enough space onscreen, your panel's parent could still choose not to give it to you. For example, if your custom panel is nested inside a Grid, the Grid may well have been set up with a hardcoded width for the column your panel occupies, in which case that's the width you'll get regardless of what you asked for during the measure phase.

It is only in the "arrange" phase that we find out how much space we have. During this phase, we must decide where to put all of our children as best we can in the space available.

You might be wondering why layout bothers with the measure phase when the amount of space we get during the arrange phase may be different. The reason for having both is that most panels try to take the measured size of their children into account during the arrange phase. You can think of the measure phase as asking every element in the tree what it would like, and the arrange phase as honoring those measurements where possible, compromising only where physical or configured constraints come into play.


Let's create a new panel type to see how the measure and arrange phases work in practice. We'll call this new panel DiagonalPanel , and it will arrange elements diagonally from the top left of the panel down to the bottom right, as Figure 2-44 shows. Each element's top-left corner will be placed where the previous element's bottom-right corner went.

Figure 2-44. Custom DiagonalPanel in action


You don't really need to write a new panel type to achieve this layoutyou could get the same effect with a Grid, setting every row and column's size to Auto. However, the same argument could be made for StackPanel and DockPanel: neither of those do anything that couldn't be done with the Grid. It's just convenient to have a simple single-purpose panel, as the Grid equivalent is a little more verbose.


To implement this custom layout, we must write a class that derives from Panel and implements the measure and arrange phases. As Example 2-36 shows, we do this by overriding the MeasureOverride and ArrangeOverride methods.

Example 2-36. Custom DiagonalPanel
using System;
using System.Windows.Controls;
using System.Windows;

namespace CustomPanel {
    public class DiagonalPanel : Panel {

        protected override Size MeasureOverride( Size availableSize ) {
            double totalWidth = 0;
            double totalHeight = 0;

            foreach( UIElement child in Children ) {
                child.Measure( new Size( double.PositiveInfinity,
                                         double.PositiveInfinity ) );
                Size childSize = child.DesiredSize;
                totalWidth += childSize.Width;
                totalHeight += childSize.Height;
            }

            return new Size( totalWidth, totalHeight );
        }

        protected override Size ArrangeOverride( Size finalSize ) {
            Point currentPosition = new Point( );

            foreach( UIElement child in Children ) {
                Rect childRect = new Rect( currentPosition, child.DesiredSize );
                child.Arrange( childRect );
                currentPosition.Offset( childRect.Width, childRect.Height );
            }

            return new Size( currentPosition.X, currentPosition.Y );
        }
    }
}

Notice that the MeasureOverride method is passed a Size parameter. If the parent is aware of size constraints that will be need to be applied during the arrange phase, it passes them here during the measure phase. For example, if this panel's parent was a Window with a specified size, the Window would pass in the size of its client area during the measure phase. However, not all panels will do this. You may find the available size is specified as being Double.PositiveInfinity in both dimensions, indicating that the parent is not informing us of any fixed constraints at this stage. An infinite available size indicates that we should simply pick whatever size is appropriate for our content.

Some elements ignore the available size, because their size is always determined by their contents. For example, our panel's simple layout is driven entirely by the natural size of its children, so it ignores the available size. Our MeasureOverride simply loops through all of the children, adding up their widths and heights. We pass in an infinite size when calling Measure on each of the children in order to use their preferred size.

You must call Measure on all of your panel's childen. If your MeasureOverride fails to Measure all of its children, the layout process may not function correctly. All elements expect to be measured before they are arranged. Their arrange logic might rely on the results of calculations performed during the measure phase. When you write a custom panel, it is your responsibility to ensure that child elements are measured and arranged at the appropriate times.


In our ArrangeOverride, we loop through all of the child elements, setting them to their preferred size, basing the position on the bottom right-hand corner of the previous element. Since this very simple layout scheme cannot adapt, it ignores the amount of space it has been given. Any child elements that do not fit will be cropped, as happens with StackPanel.

This measure-and-arrange sequence traverses the entire user interface treeall elements use this mechanism, not just panels. A custom panel is the most appropriate place to write custom layout logic for managing the arrangement of controls. However, there is one other situation in which you might want to override the MeasureOverride and ArrangeOverride methods. If you are writing a graphical element that uses the low-level visual APIs described in Chapter 7, you will need to override these methods in order for the layout system to work with your element. The code will typically be simpler than for a panel, because you will not have child elements to arrange. Your MeasureOverride will simply need to report how much space it needs, and ArrangeOverride will tell you how much space you have been given.


©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