XTab's Blog

Ged Mead's Blog at vbCity

This blog hosted by:
http://blogs.vbcity.com      
  Home :: Syndication  :: Login

AprMay 2008Jun
SMTWTFS
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

Archives

Topics

Ramblings

VB.NET

     WPF Layout - The DockPanel

Introduction

 The DockPanel probably offers you a better option than the UniformGrid in many cases. However, this layout panel too is not without its eccentricities and you can spend a lot of time tweaking and fiddling with settings in order to get the exact display you want.

 However, if your needs are simple then the DockPanel works well.   You do have to be aware of the effect of its "Pecking Order" approach to layout and distribution of space.  What this means is that, if the user resizes the window to height/width ratios that result in the elements that are higher in the pecking order grabbing all the available real estate then some lower status elements may become unacceptably distorted or even disappear completely.

 You can partly control this by use of MaxWidth, MinWidth, MinHeight and MaxHeight settings, but this isn't guaranteed to do the trick. It appears that the demands of elements higher up the pecking order override the requests of the lower, as you will see when we work through the samples that follow.

How NOT To Do It.

 I wanted to create a simple DockPanel layout that had just three elements:

  1. An Image
  2. A Button to Move To Another Image
  3. A Text Description of the Image

 That doesn't sound too difficult, does it? Of course I wanted the three elements to be displayed without any truncation of text, cropping of image or - worst of all - loss of sight of any of the elements no matter how the user resized the Window. It seemed to me that WPF should be able to achieve this easily - after all, presentation is what it is all about.

 Here was my first effort:

Code Copy
<Window x:Class="DockPanelDemo1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="DockPanelDemo1" Height="460" Width="500">
    <DockPanel  >

      
       <Image Source="Images/Pictures 106.jpg" DockPanel.Dock="Top" />

       
       <Button Margin="4" Padding="4" Background="Green" FontSize="13" DockPanel.Dock="Right"
Foreground="White" MaxHeight="60" MaxWidth="199" HorizontalAlignment="Right">
  Next Image >
   Button>

   
     <TextBlock Margin="7" FontFamily="Verdana" FontSize="15" TextWrapping="Wrap"
        DockPanel.Dock ="Left" >
        PortPatrick, Dumfries and Galloway, South West Scotland May 2006
     TextBlock>

   DockPanel>
Window>

 I think the commenting makes the steps pretty clear. Some points to note:

 The DockPanel has an Attached Property named "Dock". If you haven't come across Attached Properties, they are used in WPF in a way that allows children to hook into properties of their parent. So, in this example, each of three child elements uses the DockPanel's Dock property to request the docking position they want.

  You will see that the Image has a Dock value of Top, and that the Button and TextBlock have Right and Left respectively. As mentioned earlier, the docking is handled on a first-come, first-served basis, so the Image - first in the XAML code - gets all the available top of the Panel.

 The second item, the button, is allocated sufficient of the remaining available "right hand space" for it to completely fit. (A button automatically sizes so that it is large enough to take its content - in this case, simple text).

 The third in line TextBlock is allocated the remaining space after the other two have taken their shares in turn. (As it happens it isn't really necessary to set the TextBlock's DockPanel.Dock property to Left as I have done in the code. If you were to delete that property setting, by default it would be given all remaining space)

 Initially, the display is excellent:

  But if you resize the window so that its height is greatly reduced, the image continues to display as you would hope, but the button and TextBlock are relegated to the wastelands.

DockPanel Squashed

  Disconcertingly, if you maximize the window, this too will cause an unwanted display: The Image stretches to take 90% of the screen and the button and TextBlock are scrunched up at the bottom. Although still usable, the button's content becomes unreadable.

 By the way, if you've had some experience with WPF layouts and are sat there thinking that setting the Window's MinWidth and MinHeight to, say, 500 and 460 will fix the problem (as I did) you too will find that it doesn't. Yes, it constrains the total window size, but that ol' Alpha Male Image just muscles in and grabs more than its fair share of the space and the button and TextBlock are still left sitting on the sidelines!

A Way That Does Work.

 Instead of spending a huge amount of time setting Min and Max Widths and Heights on each of the child elements, which only brought limited success anyway, I found that if I changed the pecking order and made the image wait its turn then I got the result we wanted. I understand that the key to this is that the button and the TextBlock have their sizes controlled by the text they contain and therefore - as their needs are less - they still leave enough real estate for the image to be fully displayed too.

 Have a look at this XAML code snippet. It's not a million miles away from the original, but the order in which the three elements are created and placed has changed - and that's the key to its success.

Code Copy
<Window x:Class="DockPanelDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="DockPanelDemo" Height="440" Width="480" MinHeight="300" MinWidth="350">
   <DockPanel  >

     <Button Margin="4" Padding="4" Background="Green" FontSize="13"
      DockPanel
.Dock="Bottom" Foreground="White"
      HorizontalAlignment
="Right">
      Next Image >
     Button>

     <TextBlock Margin="7" FontFamily="Verdana" FontSize="15" TextWrapping="Wrap"
        HorizontalAlignment="Center"  DockPanel.Dock ="Top" >
        PortPatrick, Dumfries and Galloway, South West Scotland May 2006
     TextBlock>

     <Image Source="Images/Pictures 106.jpg" />
   DockPanel>

Window>

 Now, no matter what I do on the Resizing front, all three elements are visible and scaled sensibly.

 DockPanel - Elements correctly displayed.

 The eagle-eyed among you might have noticed that I slipped in a MinHeight and MinWidth value for the containing Window. I wouldn't want you to think that was some sleight of hand trick that changes anything I've said about the pecking order. With those minimum values removed, the scaling still works perfectly - except of course you eventually reach a point where the image is as tiny as my bank balance.

 Image too smll to be of use.

 It's actually quite an interesting experiment to continue to make the window smaller and smaller, because it very clearly demonstrates how each element drops off the edge in reverse pecking order as the amount of screen space available continues to reduce.

 If you continue to reduce from the size shown above, the image disappears altogether:

 Image disappears

 And as you continue to squeeze it, the next in line - the TextBlock - also gets pushed out of the nest:

 
Button only

 There are several other aspects of the DockPanel that I want to cover, but I will leave those for a second instalment. I hope this brief initial look has shown that with minimal effort it is quite easy to create docked layouts that scale perfectly as the window is resized.

posted on Monday, August 06, 2007 5:02 PM

Feedback

# Sticky Controls: The WrapPanel in WPF 8/7/2007 7:31 AM XTab's Blog


Post Feedback

Title:
Name:
Url:
Comments: 
Protected by Clearscreen.SharpHIPEnter the code you see: