Peter McGrattan’s Weblog

Silverlight, WCF, ASP.NET, AJAX, Graphics, RIA

Posts Tagged ‘ItemsPanel’

Customizing the Silverlight 2 ItemsControl with Templates

Posted by petermcg on February 15, 2009

(Code download)

The ItemsControl in Silverlight 2 is the base type for a number of list based UI controls:

ItemsControl Derived Types

It’s at a place in it’s class hierarchy that means it provides just enough to get you going with list output. Controls further down the inheritance hierarchy from ItemsControl tend to specialise it’s functionality by providing the ability to select or edit items in the list in slightly distinct ways. The items in an ItemsControl can be defined in Xaml or generated dynamically from the ItemsSource property in code.

Every aspect of the ItemsControl’s appearance from the exterior of the control, the panel that surrounds it’s items and the items themselves can be customized based on a pre-defined pattern or ‘template’ that you specify. Three properties on the ItemsControl allow you to specify three different types of template to describe three different aspects of the appearance of the final list:

Property Name

Type

Default Content

Template System.Windows.Controls.ControlTemplate ItemsPresenter containing StackPanel
ItemsPanel System.Windows.Controls.ItemsPanelTemplate StackPanel containing ContentPresenter per item
ItemTemplate System.Windows.DataTemplate ContentPresenter containing Grid

 
These defaults can be visualised in the following control hierarchy:

Default ItemsControl Template Output

The ‘Template’ property is inherited from Control and appropriately allows you to specify a ControlTemplate to define the appearance of everything about the ItemsControl outside it’s ItemsPresenter. The other two properties ‘ItemsPanel’ and ‘ItemTemplate’ are defined by the ItemsControl class itself and are concerned with the appearance of items inside the ItemsControl. More specifically the ‘ItemsPanel’ property controls the appearance of the panel that surrounds all the item’s ContentPresenters, the ‘ItemTemplate’ property customizes the appearance of the contents of each ContentPresenter.

Customizing the Default Templates

The following example shows how to customize the value of each of these three properties to produce a different control hierarchy. The sample application attached to this post makes use of the ItemsControl to position images not vertically in a StackPanel but at specific coordinates within a Canvas. The Xaml from the sample application is reproduced below along with the subsequent control hierarchy:

<UserControl x:Class="ItemsControlImages.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:app="clr-namespace:ItemsControlImages">

    <UserControl.Resources>
        <ControlTemplate x:Key="ControlTemplateKey">
            <Border x:Name="ControlTemplate_ValueOf_Template">
                <ItemsPresenter />
            </Border>
        </ControlTemplate>

        <ItemsPanelTemplate x:Key="ItemsPanelKey">
            <Grid x:Name="ItemsPanelTemplate_ValueOf_ItemsPanel" />
        </ItemsPanelTemplate>

        <DataTemplate x:Key="ItemTemplateKey">
            <Canvas x:Name="DataTemplate_ValueOf_ItemTemplate" >
                <Image Canvas.Top="{Binding Location.Y}"
                       Canvas.Left="{Binding Location.X}"
                       Source="{Binding FlagImage}" />

                <StackPanel Canvas.Top="{Binding Location.Y}"
                            Canvas.Left="{Binding Location.X}">
                    <TextBlock Text="{Binding Title}" />
                    <TextBlock Text="{Binding Location}" />

                    <StackPanel.RenderTransform>
                        <TranslateTransform Y="-32.0" />
                    </StackPanel.RenderTransform>
                </StackPanel>
            </Canvas>
        </DataTemplate>
    </UserControl.Resources>

    <Canvas x:Name="LayoutRoot">
        <Canvas.Background>
            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="#FFB2C6D5"/>
                <GradientStop Color="#FF1483D9" Offset="1"/>
            </LinearGradientBrush>
        </Canvas.Background>

        <ItemsControl Template="{StaticResource ControlTemplateKey}"
                      ItemsPanel="{StaticResource ItemsPanelKey}"
                      ItemTemplate="{StaticResource ItemTemplateKey}">

            <app:Country Title="Argentina" Location="56,218" FlagImage="Images/ARG.png" />
            <app:Country Title="China" Location="368,66" FlagImage="Images/CHN.png" />
            <app:Country Title="Ireland" Location="192,90" FlagImage="Images/IRE.png" />
            <app:Country Title="New Zealand" Location="404,225" FlagImage="Images/NZ.png" />
            <app:Country Title="United States" Location="40,80" FlagImage="Images/USA.png" />

        </ItemsControl>
    </Canvas>
</UserControl>

This Xaml produces the following control hierarchy:

Customized ItemsControl Template Output

The contents of the three custom templates are defined in the Resources section of the UserControl and bound to the relevant properties of the instance of ItemsControl. Firstly the ControlTemplate specified in the Template property has been used to surround the ItemsPresenter with a blank Border. Secondly the ItemsPanelTemplate specified in the ItemsPanel property means the ItemsPresenter now has a Grid as it’s content rather than a StackPanel. Finally the DataTemplate specified in the ItemTemplate property has completely replaced the default Grid with a Canvas containing an Image and a StackPanel. The contents of the DataTemplate are interspersed with Binding expressions to extract data from each item in the ItemsControl, in this case instances of the simple Country class shown below:

using System.ComponentModel;
using System.Windows;

namespace ItemsControlImages
{
    public class Country : INotifyPropertyChanged
    {
        private string title;
        private string flagImage;
        private Point location;

        public string Title
        {
            get
            {
                return this.title;
            }
            set
            {
                if ((object.ReferenceEquals(this.title, value) != true))
                {
                    this.title = value;
                    this.RaisePropertyChanged("Title");
                }
            }
        }

        public string FlagImage
        {
            get
            {
                return this.flagImage;
            }
            set
            {
                if ((object.ReferenceEquals(this.flagImage, value) != true))
                {
                    this.flagImage = value;
                    this.RaisePropertyChanged("FlagImage");
                }
            }
        }

        public Point Location
        {
            get
            {
                return this.location;
            }
            set
            {
                if ((this.location.Equals(value) != true))
                {
                    this.location = value;
                    this.RaisePropertyChanged("Location");
                }
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler propertyChanged = this.PropertyChanged;

            if (propertyChanged != null)
            {
                propertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }
}

This all conspires to produce the following UI:

Positioned ItemsControl Images

Note even though the Images are in an ItemsControl they are positioned at the coordinates shown by setting the value of the Left and Top attached properties of their parent Canvas to the value of the X and Y coordinates from the custom Location property via the Bindings specified in the DataTemplate assigned to the ItemsControl’s ItemTemplate property.

The images used in the sample application are from this article on WikiMedia and the control hierarchy images were produced from screenshots of the excellent Silverlight Spy 2 which I highly recommend.

Posted in ItemsControl, Silverlight, XAML | Tagged: , , , , , | 14 Comments »

 
Follow

Get every new post delivered to your Inbox.