XTab's Blog

Ged Mead's Blog at vbCity

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

JulAugust 2007Sep
SMTWTFS
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678

Archives

Topics

Ramblings

VB.NET

Tuesday, August 07, 2007 #

     WPF Layout - The WrapPanel

Introduction

 As its name implies, this kind of panel is designed to dynamically change the layout of its children by wrapping them horizontally or vertically as necessary in order to try to keep displaying them for as long as possible. Obviously, if you don't set minimum size values it will eventually become possible for the children to be cropped or finally disappear, but the WrapPanel does its best to display as much as it can.

 This can be a very useful layout panel in WPF. In my limited experience I have found that it seems to work best when its children are of equal or similar dimensions to each other. This isn't a requirement; it simply seems to look better in this case.

 As you may have seen in the earlier blog items on WPF layout panels, the UniformGrid and the DockPanel, it's very common to use layout panels as containers for other layout panels. Sometimes these will be the same kind of panel, e.g. a DockPanel within a DockPanel; sometimes not. I think that in the majority of situations you will want to use the WrapPanel as a sub-element inside another container.

WrapPanel As Root Element

 But just to see it at its most basic, the first example shows a Window which contains only a single WrapPanel.

 The scenario here is to create a group of buttons, constraining the maximum size of the window so that they will fit in line horizontally or vertically if the user decides to resize the window.

 The XAML code that does this is as follows:

Code Copy
<Window x:Class="WrapPanelAsRoot"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Root WrapPanel"  Height="270" Width="212" MinHeight="250" MaxWidth="555" >
    <WrapPanel x:Name="ButtonPanel" Background="Gainsboro">

     <Button Background="Black" Foreground="White"  Margin="12,3,12,3" Padding="3" MinWidth="75" MinHeight="34"> Open Button>
     <Button Background="Black" Foreground="White" Margin="12,3,12,3" Padding="3" MinWidth="75" MinHeight="34"> Close Button>
     <Button Background="Black" Foreground="White"  Margin="12,3,12,3" Padding="3" MinWidth="75" MinHeight="34"> StartButton>
     <Button Background="Black" Foreground="White"  Margin="12,3,12,3" Padding="3" MinWidth="75" MinHeight="34"> Pause Button>
     <Button Background="Black" Foreground="White"  Margin="12,3,12,3" Padding="3" MinWidth="75" MinHeight="34"> StopButton>

    WrapPanel>
Window>

 When first run, the window looks like this:-

  Root WrapPanel

 When the width is reduced by user action, the MinHeight setting means that there will always be enough height for all five to be shown - the WrapPanel automatically doing the wrapping as the user continues to squeeze the width.

  WrapPanel with MinHeight

 The MaxWidth is less important, as it simply stops the continued expanding of the width once there is enough space for all five buttons to be displayed horizontally. The MinHeight constraint also still applies.

WrapPanel As Sub-Element

 As mentioned above, you will probably use WrapPanels as part of a larger configuration. The following example places the same five buttons in a WrapPanel, but the WrapPanel itself is also contained inside a DockPanel.

Here's the XAML:

Code Copy
<Window x:Class="Window3"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window3" Height="300" Width="420">
    <DockPanel >
      
      <WrapPanel DockPanel.Dock="Top" Background="Gainsboro">
       <Button Background="Black" Foreground="White"  Margin="12,3,12,3" Padding="3" MinWidth="75" MinHeight="34"> Open Button>
       <Button Background="Black" Foreground="White" Margin="12,3,12,3" Padding="3" MinWidth="75" MinHeight="34"> Close Button>
       <Button Background="Black" Foreground="White"  Margin="12,3,12,3" Padding="3" MinWidth="75" MinHeight="34"> StartButton>
       <Button Background="Black" Foreground="White"  Margin="12,3,12,3" Padding="3" MinWidth="75" MinHeight="34"> Pause Button>
       <Button Background="Black" Foreground="White"  Margin="12,3,12,3" Padding="3" MinWidth="75" MinHeight="34"> StopButton>
      WrapPanel>

   
   <DockPanel>
     
     
      <ListBox Margin="5" Padding="5" Background="LightSkyBlue" DockPanel.Dock="Left" FontSize="14">
      <ListBoxItem> Classics ListBoxItem>
        <ListBoxItem> Jazz ListBoxItem>
        <ListBoxItem> Reggae ListBoxItem>
      ListBox>

      <ListBox Margin="5" Padding="5" Background="LightGray" DockPanel.Dock="Left" FontFamily="Verdana" FontSize="13" FontStyle="Italic">
       <ListBoxItem> Ride of the Valkyries ListBoxItem>
       <ListBoxItem> Piano Concerto # 1  ListBoxItem>
       <ListBoxItem> Rhapsody in Blue ListBoxItem>
      ListBox>

      
      
       <Image  Source="Blue Hills.jpg" Margin="8" />
   DockPanel>

  DockPanel>

Window>

 This starts out as:

 

 And if the user changes its size and shape, the display is still pretty decent:

 

 and:-

  and so on.

 Although I haven't done so in this example, it would be easy work to set a MinHeight and MinWidth value on the containing window to ensure that all the buttons and listboxes remained accessible and fully visible.

  In case you're wondering if it's really necessary to have so much repetition of the property attributes - such as the settings used for Button Margins, Padding, Background, etc - which are the same for each one ... you'll be pleased to hear that there is indeed a much neater, less verbose way. WPF allows you to set Styles which can be applied to controls and this is something I'll cover in a later blog.

So, that's a quick look at a fairly useful layout panel available in WPF - the WrapPanel.

posted @ 3:31 PM