Hi Folks,
I’d like for us to talk about one of the new controls in the Silverlight Toolkit – DockPanel.
In the following article we’ll deep dive into DockPanel and see how it behaves in different situations.
Setup
1. Create a new project.
2. Add a reference to the Silverlight Controls assembly (Microsoft.Windows.Controls.dll) which can be downloaded at http://codeplex.com/Silverlight.
3. Add a Silverlight Toolkit controls xmlns reference to the XAML page.
4. Add a DockPanel to the Page with LastChildFill=False. (we’ll talk about this property later in this article)
<controls:DockPanel LastChildFill="False" />
Here’s the XAML we just wrote:
<UserControl x:Class="SilverlightControlsNovember2008.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300"
xmlns:controls="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls">
<Border x:Name="LayoutRoot" Background="White" BorderBrush="Black" BorderThickness="1">
<controls:DockPanel LastChildFill="False" />
</Border>
</UserControl>
(for the purposes of this specific demo, we changed LayoutRoot to be a <Border> and not a <Grid>. That is so we could see the edge of our visual area)
Docking a single Item
Let’s add a <Button> to the top our DockPanel.
<controls:DockPanel LastChildFill="False">
<Button Content="#1" />
</controls:DockPanel>
And here’s a preview through Visual Studio XAML designer:
<Button> Fills all the available space given to the control inside our DockPanel.
So actually Button is perfect for us to learn about DockPanel, since it lets us see exactly where the control is and what the available size for it is.
As we can, the <Button> is Docked to the Left of our DockPanel.
Let’s specify a Controls:DockPanel.Dock Attached property value that would allow us to dock items to areas of the DockPanel.
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Top" Content="#1" />
</controls:DockPanel>
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Right" Content="#1" />
</controls:DockPanel>
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Bottom" Content="#1" />
</controls:DockPanel>
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Left" Content="#1" />
</controls:DockPanel>
Docking two items to opposite docking areas
Looking at the previous example it’s pretty easy to figure out what the following XAML would look like.
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Left" Content="#1" />
<Button controls:DockPanel.Dock="Right" Content="#2" />
</controls:DockPanel>
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Top" Content="#1" />
<Button controls:DockPanel.Dock="Bottom" Content="#2" />
</controls:DockPanel>
Docking the last item to Center
In our first DockPanel example we’ve set some mysterious LastChildFill property to false.
Let’s set LastChildFill=True and put an undocked button as the last child of the DockPanel.
<controls:DockPanel LastChildFill="True">
<Button controls:DockPanel.Dock="Top" Content="#1" />
<Button controls:DockPanel.Dock="Bottom" Content="#2" />
<Button Content="Filler" />
</controls:DockPanel>
It’s important to note that Even if we do set DockPanel.Dock property on the last child of a DockPanel, it would still get filled out if LastChildFill=True.
<controls:DockPanel LastChildFill="True">
<Button controls:DockPanel.Dock="Top" Content="#1" />
<Button controls:DockPanel.Dock="Bottom" Content="#2" />
<Button controls:DockPanel.Dock="Left" Content="Filler" />
</controls:DockPanel>
You can see the “DockPanel.Dock=Left” is completely ignored and the Last child is still treated as a filler.
Docking Defaults (LastChildFill=True, Dock=Left)
By default a DockPanel would always treat the last child as a Filler.
<controls:DockPanel>
<Button controls:DockPanel.Dock="Top" Content="#1" />
<Button Content="Filler" />
</controls:DockPanel>
And by default, any item not Docked to any area, will be docked to the Left.
<controls:DockPanel>
<Button Content="#1" />
<Button Content="Filler" />
</controls:DockPanel>
Let’s add a few more items so the Default Left docking would be a bit more visible.
<controls:DockPanel>
<Button Content="#1" />
<Button Content="#2" />
<Button Content="#3" />
<Button Content="Filler" />
</controls:DockPanel>
Essentially, DockPanel by default mimics a Horizontal StackPanel besides the fact that it does treat the last item as a filler.
<StackPanel Orientation="Horizontal">
<Button Content="#1" />
<Button Content="#2" />
<Button Content="#3" />
<Button Content="Filler" />
</StackPanel>
Docking Multiple elements to the same Docking area
You’ve probably noticed in the previous example that the DockPanel stacks items on the same Area.
Let’s have a look at stacking multiple items on all sides.
<controls:DockPanel>
<Button controls:DockPanel.Dock="Top" Content="#1" />
<Button controls:DockPanel.Dock="Top" Content="#2" />
<Button controls:DockPanel.Dock="Top" Content="#3" />
<Button Content="Filler" />
</controls:DockPanel>
<controls:DockPanel>
<Button controls:DockPanel.Dock="Right" Content="#1" />
<Button controls:DockPanel.Dock="Right" Content="#2" />
<Button controls:DockPanel.Dock="Right" Content="#3" />
<Button Content="Filler" />
</controls:DockPanel>
<controls:DockPanel>
<Button controls:DockPanel.Dock="Bottom" Content="#1" />
<Button controls:DockPanel.Dock="Bottom" Content="#2" />
<Button controls:DockPanel.Dock="Bottom" Content="#3" />
<Button Content="Filler" />
</controls:DockPanel>
<controls:DockPanel>
<Button controls:DockPanel.Dock="Left" Content="#1" />
<Button controls:DockPanel.Dock="Left" Content="#2" />
<Button controls:DockPanel.Dock="Left" Content="#3" />
<Button Content="Filler" />
</controls:DockPanel>
The order in which items are stacked is based on the first rule of DockPanel.
The First Rule of Fight Club: You Don’t talk about Fight Club
The First Rule of DockPanel: The order of DockPanel Children’s determines their placement based on precedence
Admittedly it’s not as dramatic as fight club, but it’s still true.
Consider these trivial DockPanel samples:
<controls:DockPanel>
<Button controls:DockPanel.Dock="Left" Content="#1" />
<Button controls:DockPanel.Dock="Left" Content="#2" />
<Button Content="Filler" />
</controls:DockPanel>
<controls:DockPanel>
<Button controls:DockPanel.Dock="Left" Content="#2" />
<Button controls:DockPanel.Dock="Left" Content="#1" />
<Button Content="Filler" />
</controls:DockPanel>
The #1 and #2 Items are placed based on the order of the DockPanel children.
Although that on the surface they’re both docked to the Left exactly, one has precedence over the other.
The order of DockPanel Children’s determines their placement based on precedence.
Docking Two elements with intersecting Docking areas
We mentioned Precedence, That is also relevant for Intersecting items.
Have a look at these two DockPanels.
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Top" Content="#1" />
</controls:DockPanel>
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Left" Content="#1" />
</controls:DockPanel>

Let’s illustrate how this collision would look like: (done with mspaint, not an actual print-screen)
Now, it’s obvious that one of these items would need to get the Top-left corner, but which one?
Let’s write some code, run it and we’ll see.
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Top" Content="#1" />
<Button controls:DockPanel.Dock="Left" Content="#2" />
</controls:DockPanel>
And if we change the order of the buttons:
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Left" Content="#2" />
<Button controls:DockPanel.Dock="Top" Content="#1" />
</controls:DockPanel>
So, as we can see – In the first example Button #1 was placed first and it got precedence over Button #2 for the top-left corner.
And in the second example Button #2 was placed first and it got precedence over Button #1 for the top-left corner.
Let’s see this at work with other docking areas.
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Right" Content="#1" />
<Button controls:DockPanel.Dock="Bottom" Content="#2" />
</controls:DockPanel>
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Bottom" Content="#1" />
<Button controls:DockPanel.Dock="Right" Content="#2" />
</controls:DockPanel>
So, we can clearly see that the order of items in the DockPanel determines who is docked first to where.
Docking Multiple elements to intersecting Docking areas
Let’s follow up on the last sample with more than one item per docking area.
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Bottom" Content="#1" />
<Button controls:DockPanel.Dock="Bottom" Content="#2" />
<Button controls:DockPanel.Dock="Bottom" Content="#3" />
<Button controls:DockPanel.Dock="Right" Content="#4" />
</controls:DockPanel>
So, Button #1 is docked first to the bottom area, followed by buttons #2 and #3, and finally Button #4 is docked to the Right.
Let’s put more items on the Right docking area.
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Bottom" Content="#1" />
<Button controls:DockPanel.Dock="Bottom" Content="#2" />
<Button controls:DockPanel.Dock="Bottom" Content="#3" />
<Button controls:DockPanel.Dock="Right" Content="#4" />
<Button controls:DockPanel.Dock="Right" Content="#5" />
<Button controls:DockPanel.Dock="Right" Content="#6" />
</controls:DockPanel>
Continuing for where the last sample left off, Button #4 is the first control docked to the right, followed by Button #5 and finally Button #6.
And we’ll finish this sample by adding Top docked buttons and Left docked buttons.
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Bottom" Content="#1" />
<Button controls:DockPanel.Dock="Bottom" Content="#2" />
<Button controls:DockPanel.Dock="Bottom" Content="#3" />
<Button controls:DockPanel.Dock="Right" Content="#4" />
<Button controls:DockPanel.Dock="Right" Content="#5" />
<Button controls:DockPanel.Dock="Right" Content="#6" />
<Button controls:DockPanel.Dock="Top" Content="#7" />
<Button controls:DockPanel.Dock="Top" Content="#8" />
<Button controls:DockPanel.Dock="Top" Content="#9" />
<Button controls:DockPanel.Dock="Left" Content="#10" />
<Button controls:DockPanel.Dock="Left" Content="#11" />
<Button controls:DockPanel.Dock="Left" Content="#12" />
</controls:DockPanel>
First, Buttons #1, #2 & #3 Get placed on the bottom.
Second, Buttons #4, #5 & #6 get placed on the right, using up remaining height in the DockPanel.
Third, Buttons #7, #8 & #9 get placed on the top, using up remaining width in the DockPanel.
Lastly, Buttons #10, #11 & #12 get placed on the Left, using up remaining Height in the DockPanel (after placing both Bottom and Top buttons).
So again – The order of DockPanel Children’s determines their placement based on precedence.
Let’s mix it up a bit by alternating top buttons and left buttons.
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Bottom" Content="#1" />
<Button controls:DockPanel.Dock="Right" Content="#2" />
<Button controls:DockPanel.Dock="Bottom" Content="#3" />
<Button controls:DockPanel.Dock="Right" Content="#4" />
<Button controls:DockPanel.Dock="Bottom" Content="#5" />
<Button controls:DockPanel.Dock="Right" Content="#6" />
</controls:DockPanel>
We can see that items are weaved into the DockPanel, based on their order.
Spiral Sample
One last final sample for DockPanel is the Spiral sample by Ted Glaza (a developer on the Silverlight Toolkit team) and slightly changed for this blog post.
<controls:DockPanel LastChildFill="False">
<Button controls:DockPanel.Dock="Left" Background="LightBlue" Content="#1" />
<Button controls:DockPanel.Dock="Top" Background="LightCoral" Content="#2" />
<Button controls:DockPanel.Dock="Right" Background="LightGreen" Content="#3" />
<Button controls:DockPanel.Dock="Bottom" Background="LightYellow" Content="#4" />
<Button controls:DockPanel.Dock="Left" Background="LightGreen" Content="#5" />
<Button controls:DockPanel.Dock="Top" Background="LightYellow" Content="#6" />
<Button controls:DockPanel.Dock="Right" Background="LightBlue" Content="#7" />
<Button controls:DockPanel.Dock="Bottom" Background="LightCoral" Content="#8" />
<Button controls:DockPanel.Dock="Left" Background="LightGray" Content="#9" />
<Button controls:DockPanel.Dock="Top" Background="LightCoral" Content="#10" />
<Button controls:DockPanel.Dock="Right" Background="LightGreen" Content="#11" />
<Button controls:DockPanel.Dock="Bottom" Background="LightBlue" Content="#12" />
<Button controls:DockPanel.Dock="Left" Background="LightCoral" Content="#13" />
<Button controls:DockPanel.Dock="Top" Background="LightGoldenrodYellow" Content="#14" />
<Button controls:DockPanel.Dock="Right" Background="LightYellow" Content="#15" />
<Button controls:DockPanel.Dock="Bottom" Background="LightGreen" Content="#16" />
<Button controls:DockPanel.Dock="Left" Background="LightYellow" Content="#17" />
<Button controls:DockPanel.Dock="Top" Background="LightCoral" Content="#18" />
<Button controls:DockPanel.Dock="Right" Background="LightBlue" Content="#19" />
<Button controls:DockPanel.Dock="Bottom" Background="LightGreen" Content="#20" />
<Button controls:DockPanel.Dock="Left" Background="LightBlue" Content="#21" />
<Button controls:DockPanel.Dock="Top" Background="LightGreen" Content="#22" />
<Button controls:DockPanel.Dock="Right" Background="LightCoral" Content="#23" />
<Button controls:DockPanel.Dock="Bottom" Background="LightYellow" Content="#24" />
</controls:DockPanel>
Pretty, isn’t it?
-- Justin Angel
Microsoft Silverlight Program Manager