Wednesday, November 25, 2009

ItemsControl – A simple way to edit and display lists of objects

This control makes me remind of the Repeater control in ASP.NET. It is quite easy to create a very simple list of objects using it. It simply creates one instance of the controls inside the DataTemplate tag per each element in the enumerable object that is bound to ItemsSource.

   1: <navigation:Page x:Class="PlayWithSilverlightControls.Views.PlayWithItemsControl"
   2:            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   5:            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   6:            mc:Ignorable="d"
   7:            xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
   8:            d:DesignWidth="640" d:DesignHeight="480"
   9:            Title="PlayWithItemsControl Page">
  10:  
  11:     <Grid x:Name="LayoutRoot">
  12:         <Grid.RowDefinitions>
  13:             <RowDefinition Height="*" />
  14:             <RowDefinition Height="30" />
  15:         </Grid.RowDefinitions>
  16:         <ItemsControl ItemsSource="{Binding ModelItems}">            
  17:             <ItemsControl.ItemTemplate>
  18:                 <DataTemplate>
  19:                     <StackPanel Margin="3,10,0,0">
  20:                         <Rectangle Height="2" Fill="Black" />
  21:                         <TextBlock Text="{Binding Name}" />
  22:                         <TextBox Text="{Binding Comment}" />
  23:                     </StackPanel>
  24:                 </DataTemplate>
  25:             </ItemsControl.ItemTemplate>
  26:         </ItemsControl>
  27:         <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right" Height="25">
  28:             <Button Content="Submit" Width="150"/>
  29:             <Button Content="Cancel" Width="150"/>
  30:         </StackPanel>
  31:     </Grid>
  32: </navigation:Page>

I used this very simple ViewModel to render some data:

   1: public class Model
   2:     {
   3:         public string Name
   4:         {
   5:             get;
   6:             set;
   7:         }
   8:  
   9:         public string Comment
  10:         {
  11:             get;
  12:             set;
  13:         }
  14:     }
  15:  
  16:     public class PlayWithItemsControlViewModel
  17:     {
  18:         private ObservableCollection<Model> items = new ObservableCollection<Model>();
  19:  
  20:         public PlayWithItemsControlViewModel()
  21:         {
  22:             this.items.Add(new Model { Name = "Model A" });
  23:             this.items.Add(new Model { Name = "Model B" });
  24:             this.items.Add(new Model { Name = "Model C" });
  25:             this.items.Add(new Model { Name = "Model D" });
  26:             this.items.Add(new Model { Name = "Model E" });
  27:         }
  28:  
  29:         public IEnumerable<Model> ModelItems
  30:         {
  31:             get
  32:             {
  33:                 return this.items;
  34:             }
  35:         }
  36:     }

The Model class is not implementing core interfaces such as INotifyPropertyChanged or IEditableObject and therefore most Silverlight features will not work with it. I hope to post some notes on how these interfaces can be implemented and used to enable those features.

We can quickly see the results by placing this code on the view code behind:

   1: // Executes when the user navigates to this page.
   2: protected override void OnNavigatedTo(NavigationEventArgs e)
   3: {
   4:      this.DataContext = new PlayWithItemsControlViewModel();
   5: }

I think it is a good practice to use the ViewModel as the DataContext of the Page and to define bindings assuming just that.

To host it create a Navigation application and go to the MainPage.xaml and add a new navigation button at the bottom of the xaml:

   1: <Rectangle x:Name="Divider2" Style="{StaticResource DividerStyle}"/>
   2:  
   3: <HyperlinkButton x:Name="Link3" Style="{StaticResource LinkStyle}" 
   4:     NavigateUri="/PlayWithItemsControl" TargetName="ContentFrame" Content="Items Control"/>

Have fun,

No comments: