Silverlight Recipes : Controls - Creating a Custom Layout Container (part 3)

- How To Install Windows Server 2012 On VirtualBox
- How To Bypass Torrent Connection Blocking By Your ISP
- How To Install Actual Facebook App On Kindle Fire
3/4/2015 8:26:08 AM
4.1. Using the WrapPanel

Let's consider using the WrapPanel in a user interface. One straightforward option is to use it in similar fashion to a StackPanel:

<wrappanellib:WrapPanel Orientation="Horizontal">
<TextBlock Text="Child 1"/>
<TextBlock Text="Child 2"/>
<TextBlock Text="Child 3"/>
<TextBlock Text="Child 4"/>
<TextBlock Text="Child 5"/>
<TextBlock Text="Child 6"/>
<TextBlock Text="Child 7"/>
<TextBlock Text="Child 8"/>
<Button Content="Child 9" Width="60" Height="30"/>
<Button Content="Child 10" Width="70" Height="30"/>
<Button Content="Child 11" Width="60" Height="30"/>
<RadioButton Content="Child 12" Width="90" Height="30"/>
<RadioButton Content="Child 13" Width="60" Height="30"/>
<Button Content="Child 14" Width="80" Height="30"/>
<Button Content="Child 15" Width="60" Height="30"/>

This code shows the standard XAML usage pattern where all children, a mixed bag of controls in this case, are listed within the WrapPanel declaration, much in the fashion of any other layout container. You should be able to cut and paste this code in your own sample application and use it as is. Just remember to reference the assembly from the sample code, and create a namespace mapping (you have mapped the wrappanellib namespace here).

One of the interesting usages of a panel is to assist in the layout process of an ItemsControl, which is the primary base control for visually representing a collection of many items. ItemsControl exposes a property named ItemsPanel of type ItemsPanelTemplate that can be defined in terms of any type that extends Panel. A better control is the ListBox, which extends the ItemsControl and, by virtue of that, uses a panel internally for layout. Let's see how to replace the layout panel for a ListBox and control some of the panel's properties as well.

Listing 2 shows the XAML for a page with a ListBox in it, with its default panel replaced with your own WrapPanel from this recipe.

Listing 2. XAML for a ListBox using the WrapPanel for layout
<UserControl x:Class="Recipe5_9.MainPage"
Width="585" Height="440">

<local:ImagesCollection x:Key="dsImages" />

<DataTemplate x:Key="dtImageItem">
<Grid Background="#007A7575" Margin="10,10,10,10" >

<Rectangle Fill="#FF7A7575" Stroke="#FF000000"
RadiusX="5" RadiusY="5"/>
<Image Margin="10,10,10,10" Width="50" Height="50"
Source="{Binding ImageFromResource}"/>


<Style TargetType="ListBox" x:Key="STYLE_WrapPanelListBox">
<Setter Property="ItemsPanel">
<wrappanellib:WrapPanel Orientation="{Binding CurrentOrientation}"
Width="600" Height="600"/>



<Grid x:Name="LayoutRoot" Background="White">
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<ListBox x:Name="lbxWrapPanelTest" Grid.Row="0"
ItemTemplate="{StaticResource dtImageItem}"
ItemsSource="{StaticResource dsImages}"
Style="{StaticResource STYLE_WrapPanelListBox}">
<StackPanel Orientation="Horizontal" Grid.Row="1">
<RadioButton Content="Horizontal Arrangement" Margin="0,0,20,0"
GroupName="OrientationChoice" x:Name="rbtnHorizontal"
Checked="rbtnHorizontal_Checked" IsChecked="True"/>
<RadioButton Content="Vertical Arrangement" Margin="0,0,0,0"
GroupName="OrientationChoice" x:Name="rbtnVertical"


The first thing to note is the ItemsPanelTemplate definition for the ListBox. The internal implementation of the ListBox in the framework uses a StackPanel as the panel, but you redefine it to use your own WrapPanel and set it as the value of the ItemsPanel property in a style targeting a ListBox. You then apply the style to the ListBox lbxWrapPanelTest. We will come back to this definition in a moment.

Also notice that lbxWrapPanelTest gets its data from a data source named dsImages pointing to a collection named ImagesCollection. The ItemTemplate is set to a data template dtImageItem that displays some images contained in dsImages; each image is encapsulated in a type named CustomImageSource.

Listing 3 shows the code for CustomImageSource and ImagesCollection.

Listing 3. Code for CustomImageSource and ImagesCollection types
using System.Windows.Media.Imaging;
using System.Reflection;
using System.Collections.Generic;

namespace Recipe5_9
public class CustomImageSource

public string ImageName { get; set; }
private BitmapImage _bitmapImage;
public BitmapImage ImageFromResource
if (_bitmapImage == null)
_bitmapImage = new BitmapImage();

return _bitmapImage;
public class ImagesCollection : List<CustomImageSource>
public ImagesCollection()
Assembly thisAssembly = this.GetType().Assembly;
List<string> ImageNames =
new List<string>(thisAssembly.GetManifestResourceNames());

foreach (string Name in ImageNames)
if (Name.Contains(".png"))
this.Add(new CustomImageSource { ImageName = Name });

The images used in this sample are embedded as resources in the project assembly. ImagesCollection uses GetManifestResourceNames() to get a collection of the string names of all the embedded resources. It then iterates over the collection of resource names and uses GetManifestResourceStream() to acquire each resource as a stream. It creates a new CustomImageSource for each one ending with the .png extension indicating an image resource, and the CustomImageSource type constructor loads the image.

Let's take another look at that ItemsPanelTemplate definition. Once the ItemsPanel property is set on the ListBoxItem, the panel instance that is created internally by the ListBox is not made available to your application code in any way. However, there may be a need to access properties on the underlying panel from application code. An example could be the need to change your WrapPanel's Orientation property to influence the ListBox's layout. However, since the panel is not directly exposed, you need to take a slightly indirect approach to this.

Inside the ItemsPanelTemplate declaration, the WrapPanel has full access to the DataContext of its parent ListBox lbxWrapPanelTest. This gives you a way to bind a property exposed by the panel to application data, as long as that data is made available through the ListBox's DataContext. As shown in Listing 1, you bind the WrapPanel.Orientation property to the CurrentOrientation property of some data item. Further, you have two RadioButtons on the page with Checked event handlers defined in the codebehind. Listing 4 shows the codebehind for the page.

Listing 4 . Codebehind for the MainPage hosting the ListBox
using System.Windows.Controls;
using System.ComponentModel;

namespace Recipe5_9
public partial class MainPage : UserControl
ListBoxPanelOrientation CurrentLbxOrientation =
new ListBoxPanelOrientation { CurrentOrientation = Orientation.Horizontal };
public MainPage()
lbxWrapPanelTest.DataContext = CurrentLbxOrientation;

private void rbtnHorizontal_Checked(object sender,
System.Windows.RoutedEventArgs e)
CurrentLbxOrientation.CurrentOrientation = Orientation.Horizontal;

private void rbtnVertical_Checked(object sender,
System.Windows.RoutedEventArgs e)
CurrentLbxOrientation.CurrentOrientation = Orientation.Vertical;
public class ListBoxPanelOrientation : INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;

private Orientation _Current;
public Orientation CurrentOrientation
get { return _Current; }

_Current = value;
if (PropertyChanged != null)
new PropertyChangedEventArgs("CurrentOrientation"));

The ListBoxPanelOrientation type exposes the CurrentOrientation property enabled with property change notification. You construct and initialize an instance of ListBoxPanelOrientation, and set it to the ListBox's DataContext. This causes the internal WrapPanel instance to adopt this orientation through the binding discussed earlier. In the Checked event handlers of the RadioButtons, you change the CurrentOrientation value, which causes the ListBox to change its orientation dynamically, again because of the property change notification flowing back to the WrapPanel through the binding.

Figure 1 shows the ListBox and the contained WrapPanel in action.

Figure 1. A ListBox using the WrapPanel with different orientations

Top 10
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
programming4us programming4us