Saturday, August 07, 2010

Silverlight 4.0 Tutorial (6 of N): Working with the ItemsControl

Read Previous Posts: Part1, Part2, Part3, Part4, Part5

In this part of the series we will build the event agenda

- First let’s try to make some room on the UI for the agenda, add a new row to the LayoutRoot grid, make sure that the attendees ListBox has RowSpan=2, then move the DataForm to the lower right cell, we will display the agenda in the upper right cell, Now our home page should look like the following

Home page

- To build the agenda let’s recall our data model, we have a table TimeSlot that contains the different time slots in the event, each session is assigned to one time slot and each time slot can have one or more session.

- We will need to retrieve all the time slots along with the sessions in each time slot, to do this go to the RegistrationDomainService.cs file in the RegistrationBooth.Web project, change the GetTimeSlots method as follows

  1. public IQueryable<TimeSlot> GetTimeSlots()
  2.         {
  3.             return this.ObjectContext.TimeSlots.Include("Sessions");
  4.         }

- You will need also to make a small change in the RegistrationDomainService.metadata.cs file, find the TimeSlotMetadata class and add the attribute [Include] to the property Sessions as follows

  1. [Include]
  2.             public EntityCollection<Session> Sessions { get; set; }

- Now back to Home.xaml in Visual Studio, from the Data Sources Tool window click the down arrow beside the TimeSlot entity,  select “None” for the control used to render this entity as we will create a custom UI to represent this entity, drag and drop the TimeSlot entity on the page, this will create the DomainDataSource control, rename it to timeSlotDomainDataSource

Data Sources

- Switch back to Blend, from the assets tool window add the ItemsControl to the Home.xaml page, place it in the top right cell, rename it to icAgenda.

- Right click the items control, select Auto Size->Fill.

- Right click the items control, select Data bind ItemsSource to Data, in the Create Date Binding dialog box go to the Element Property tab select the timeSlotDomainDataSource element from the left list box and select the Data property from the right list box.

Create Data Binding

-  Right click the items control, select Edit Additional Templates –> Edit Generated Items (ItemTemplate) –> Create Empty.

Create ItemTemplate

- In the Create DataTemplate Resource dialog, set the key to timeSlotDataTemplate, click Ok, Blend will switch to the design of the ItemTemplate which initially contain empty grid.

Create DataTemplate Resource

- Use the designer to add a column to the grid as follows


- In the left column add a Rectangle, set the Fill property to white solid color brush, set the RadiusX and RadiusY properties to 10 to have a rounded rectangle, increase the width of the rectangle to overlap the right column (as shown below)

Rounded Rectabgle

- Add another rectangle to the right column, set the Fill property to white solid color brush, set the RadiusX and RadiusY properties to 10 to have a rounded rectangle, right click the rectangle select Auto Size->Fill, the data template should look like the below image


- In the left column rectangle we will display the time slot start and end times (ex: 09:00 –10:00), to do this add a StackPanel to this column, set the Orientation to Horizontal, in the StackPanel add 3 TextBlocks, set the Text of the middle one to “ – “, set the Text of the first one to a binding to the StartTime property, set the Text of the third one to a binding to the EndTime property, for both bindings use a StringFormat=’HH:mm tt’ to display the time only, the markup for the TextBlocks is shown below

  1. <TextBlock TextWrapping="Wrap" Text="{Binding StartTime, StringFormat='HH:mm tt'}" />
  2.                 <TextBlock TextWrapping="Wrap" Text=" - " />
  3.                 <TextBlock TextWrapping="Wrap" Text="{Binding EndTime, StringFormat='HH:mm tt'}" />

- in the right column we will display all the sessions in the corresponding TimeSlot, to do this add ItemsControl to the right column, name it icSessions, set its ItemsSource property to binding to the Sessions Property.

- Right click the icSessions control, select  Edit Additional Templates –> Edit Generated Items (ItemTemplate) –> Create Empty.

- In the Create DataTemplate Resource dialog, set the key to sessionDataTemplate, click Ok, Blend will switch to the design of the ItemTemplate which initially contain empty grid.

Create Data Template Resource

- We will create a small template for the session that shows the session title, location and description, so use three textblocks and bind them to the Title and Location and Description properties respectively, the xaml of the sessionDateTemplate is shown below

  1. <DataTemplate x:Key="sessionDataTemplate">
  2.             <Grid Margin="10,0,0,20">
  3.                 <Grid.RowDefinitions>
  4.                     <RowDefinition></RowDefinition>
  5.                     <RowDefinition></RowDefinition>
  6.                 </Grid.RowDefinitions>
  7.                 <StackPanel Orientation="Horizontal" Grid.Row="0" >
  8.                     <TextBlock FontSize="16" FontWeight="Bold" Text="{Binding Title}"
  9.                     TextWrapping="Wrap" Width="400" />
  10.                     <TextBlock FontSize="16" FontWeight="Bold" Text=" - "/>    
  11.                     <TextBlock FontSize="16" FontWeight="Bold" Text="{Binding Location}"/>
  12.                 </StackPanel>
  13.                 <TextBlock FontSize="10" TextWrapping="Wrap"   Text="{Binding Description}"
  14.                 Width="400" Grid.Row="1" HorizontalAlignment="Left" />
  15.             </Grid>
  16.         </DataTemplate>

- Try and run the application, i already have two time slots in my database, the first time slot has two sessions and the second has one session, the UI will look like the following

the ItemsControl doesn't scroll

- As you can see the problem is that the ItemsControl doesn’t provide scrolling, we have to change the Template of the ItemsControl to support this, this is a pretty easy task, right click the icSessions control, select Edit Template-> Create Empty

Edit ItemsControl Template

- In the Create Control Template Resource name it ItemsControlScrollableControlTemplate and click Ok

- Use the following xaml for this template

  1. <ControlTemplate x:Key="ItemsControlScrollableControlTemplate" TargetType="ItemsControl">
  2.             <ScrollViewer x:Name="ScrollViewer" Padding="{TemplateBinding Padding}" BorderThickness="0">
  3.                 <ItemsPresenter />
  4.             </ScrollViewer>
  5.         </ControlTemplate>

- We need also to use the same template for the outer ItemsControl (icAgenda), to do this right click the control, select Edit Template-> Apply Resource->  ItemsControlScrollableControlTemplate

Apply Control Template

- Run the application, you can now scroll both the inner and the outer ItemsControl

Scrollable ItemsControl

See you in the next post

You can download the code from Here