5,446,542 members and growing! (16,860 online)
Email Password   helpLost your password?
Web Development » Silverlight » General License: The Code Project Open License (CPOL)

WrapPanel for Silverlight 2.0

By lneir

Simple example of custom panel using Silverlight 2.0
C# (C# 1.0, C# 2.0, C# 3.0, C#), .NET (.NET, .NET 3.5, .NET 3.0)

Posted: 5 Mar 2008
Updated: 6 Mar 2008
Views: 10,218
Bookmarked: 7 times
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
10 votes for this Article.
Popularity: 4.05 Rating: 4.05 out of 5
0 votes, 0.0%
1
1 vote, 11.1%
2
0 votes, 0.0%
3
5 votes, 55.6%
4
3 votes, 33.3%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article

Introduction

One of the most exciting features of Silverlight 2.0 (beta 1) is the ability to create custom panels - just like WPF! Silverlight 2.0 (beta 1) comes with three panels: Canvas, Grid, and StackPanel. Many people will miss other popular panels already included with WPF. This article shows how to build a simple WrapPanel using the extensibility features available with Silverlight 2.0.

The completed code is available here: Download WrapPanel.zip - 891.61 KB

Background

A custom panel in Silverlight (and WPF) contains two important parts: Measure and Arrange. This is a two-pass recursive system. The first round measures the size of all children in the panel. In a recursive manner, all children in turn measure the size of their children and so on. In the next round, the children of the panel are arranged using whatever algorithm you like.

For a complete description of building a custom panel see the MSDN article: http://msdn2.microsoft.com/en-us/library/ms745058.aspx

Using the code

The first important aspect of the custom WrapPanel is to inherit from Panel. Panel is an abstract class from which all panels must derive. The Orientation dependency property determines whether WrapPanel flows vertically or horizontally.

public class WrapPanel : Panel
{

  public Orientation Orientation
  { 
    get { return (Orientation)GetValue(OrientationProperty); }
    set { SetValue(OrientationProperty, value); }
   }

   public static readonly DependencyProperty OrientationProperty =
     DependencyProperty.Register("Orientation", typeof(Orientation), typeof(WrapPanel), null);

 public WrapPanel()
 {
   // default orientation
   Orientation = Orientation.Horizontal;
 }

Next we must override the Measure function. The input parameter 'availableableSize' to MeasureOverride tells the panel how much size it has to work with. This size is given to the panel by it's parent. The most important aspect in measuring each child is to indicate to each child their allowed size. In this simple example, we are just saying to each child that they can have the whole space of the panel. The result of the measuring yields a 'DesiredSize' for each child - this desired size will be used when arrange the children.

protected override Size MeasureOverride(Size availableSize)
{
  foreach (UIElement child in Children)
  {
    child.Measure(new Size(availableSize.Width, availableSize.Height)); 
  }

  return base.MeasureOverride(availableSize);
 }
        

Finally, we must override the Arrange method. Here, we will position each child in the panel. In our case here we position items either horizontally or vertically. In the horizontal case, we arrange the children (left to right) until the right edge of panel is reached then we move to the next line and continuing laying out the children (left to right).

protected override Size ArrangeOverride(Size finalSize)
{
  Point point = new Point(0,0);
  int i = 0;

  if (Orientation == Orientation.Horizontal)
  {
    double largestHeight = 0.0;

    foreach (UIElement child in Children)
    {
      child.Arrange(new Rect(point, new Point(point.X + child.DesiredSize.Width, point.Y + child.DesiredSize.Height)));

      if (child.DesiredSize.Height > largestHeight)
         largestHeight = child.DesiredSize.Height;

      point.X = point.X + child.DesiredSize.Width;

      if ((i + 1) < Children.Count)
      {
        if ((point.X + Children[i + 1].DesiredSize.Width) > finalSize.Width)
        {
           point.X = 0;
           point.Y = point.Y + largestHeight;
           largestHeight = 0.0;
         }
       }
       i++;
     }
    }
    else
    {
       double largestWidth = 0.0;

       foreach (UIElement child in Children)
       {
         child.Arrange(new Rect(point, new Point(point.X + child.DesiredSize.Width, point.Y + child.DesiredSize.Height)));

         if (child.DesiredSize.Width > largestWidth)
           largestWidth = child.DesiredSize.Width;

          point.Y = point.Y + child.DesiredSize.Height;

          if ((i + 1) < Children.Count)
          {
            if ((point.Y + Children[i + 1].DesiredSize.Height) > finalSize.Height)
            {
              point.Y = 0;
              point.X = point.X + largestWidth;
              largestWidth = 0.0;
             }
           }

           i++;
          }
        }

    return base.ArrangeOverride(finalSize);
   }
 }
}

Points of Interest

Note, the WrapPanel provided here functions mostly like the WPF WrapPanel. I noticed some minor differences but have not had time to fix. Feel free to send along your suggested changed.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

lneir


I work in the Bay Area developing software using .NET/C#, WPF, and Silverlight.
Occupation: Software Developer (Senior)
Company: Pinnacle Systems/Avid
Location: United States United States

Other popular Silverlight articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 8 of 8 (Total in Forum: 8) (Refresh)FirstPrevNext
Subject  Author Date 
Questionmodified to behave as animating panelmemberMember 285468319:22 3 Jul '08  
AnswerRe: modified to behave as animating panelmemberlneir8:33 4 Jul '08  
GeneralThanks!memberSeth Webster17:23 13 Jun '08  
GeneralWrappanel inside another panelmemberMember 38021188:33 22 May '08  
GeneralRe: Wrappanel inside another panelmembervRud11:01 7 Jun '08  
GeneralRe: Wrappanel inside another panelmemberchris rothery3:32 14 Aug '08  
GeneralDoesn't work inside ScrollViewermemberraulgspan16:45 27 Mar '08  
GeneralRe: Doesn't work inside ScrollViewermemberlneir17:05 27 Mar '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 6 Mar 2008
Editor:
Copyright 2008 by lneir
Everything else Copyright © CodeProject, 1999-2008
Web11 | Advertise on the Code Project