WPF Image Viewer Part 4, Data Templates and Resources

This is a part of the WPF image viewer tutorial: Introduction, Part 1, Part2 and Part 3.

I promised something nice and we got all the way to the 4th post with a program that displays a list of filenames, it's time to start seeing some images.

The WPF list box control isn't the old Windows list box, while the old list box could only display a list of strings the WPF list box can display any list, if we tried to display buttons we would have got a list of completely functional buttons you can press – but we used a list of MyImage and since WPF doesn't know how to display MyImage it used the ToString method and displayed the strings.

Let's teach our program how to display MyImage, just replace our previous list box definition with:

<ListBox ItemsSource="{Binding AllImages}">
   <ListBox.ItemTemplate>
      <DataTemplate>
         <Image Source="{Binding Image}" Width="100" Height="100"/>
      </DataTemplate>
   </ListBox.ItemTemplate>
</ListBox>

Now run this and we get a list box with images inside instead of text.

This magic is done by ItemsControl, every control that displays a list of items (including ListBox) inherits from ItemsControl and it let us determine how items are displayed by setting the item template, the items control just duplicates the template's content for every item in the list (with the DataContext set to the item – so data binding is easy).

There's just one more thing we have to cover before moving on, if you tried to write this code in developer studio you have seen that it really doesn't like the way we set the item template, the XAML editor shows it as an error and there is no Intellisense, the reason is that while what we did is valid XAML it's not the way it should be done – templates should be defined in a resource and not inside the control.

What is a resource? Since it's a quick tutorial and not an in-depth explanation (for an in-depth explanation you should buy this book) I'll show you a short example, this XAML:

<StackPanel>
   <Label Content="Text1">
      <Label.Background>
         <SolidColorBrush Color="Blue"/>
      </Label.Background>
   </Label>
   <Label Content="Text2">
      <Label.Background>
         <SolidColorBrush Color="Blue"/>
      </Label.Background>
   </Label>
</StackPanel>

Does the same as this C# code:

StackPanel p = new StackPanel();
Label l1 = new Label();
l1.Content = "Text1";
l1.Background = new SolidColorBrush(Colors.Blue);
p.Children.Add(l1);
Label l2 = new Label();
l2.Content = "Text2";
l2.Background = new SolidColorBrush(Colors.Blue);
p.Children.Add(l2);

Look how every label get's a new copy of the brush? Good, now this XAML:

<StackPanel>
   <StackPanel.Resources>
      <SolidColorBrush x:Key="TheBrush" Color="Blue"/>
   </StackPanel.Resources>
   <Label Content="Text1" Background="{StaticResource TheBrush}"/>
   <Label Content="Text2" Background="{StaticResource TheBrush}"/>
</StackPanel>

Does the same as this C# code:

StackPanel p = new StackPanel();
SolidColorBrush MyBrush = new SolidColorBrush(Colors.Blue);
Label l1 = new Label();
l1.Content = "Text1";
l1.Background = MyBrush;
p.Children.Add(l1);
Label l2 = new Label();
l2.Content = "Text2";
l2.Background = MyBrush;
p.Children.Add(l2);

See? Both labels use the same brush object.

Now let's move our template into the window's resources.

All the following code just after the <Window> tag, before the <Grid> tag:

<Window.Resources>
   <DataTemplate x:Key="MyImageTemplate">
      <Image Source="{Binding Image}" Width="100" Height="100"/>
   </DataTemplate>
</Window.Resources>

And change the list box definition to:

<ListBox ItemsSource="{Binding AllImages}" ItemTemplate="{StaticResource MyImageTemplate}" />

And we're done.

There are just few simple rules to remember about resources:

  • Just about everything can have resources – we defined the resource in the window's resource dictionary, we could have used the grid that's directly inside the resource if we wanted to.
  • You can use resources only inside the element that defined them – in our case we use the root element so we can use the template anywhere in the XAML file. Resources are references using keys, you specify the key with the x:Key attribute, the keys are case sensitive.
  • You can only use a resource after it is defined I we could theoretically put the Window.Resources element at the end of the file just before the tag, but then we would have nowhere to use it.

That's it for this part, in the next part we'll see how the common panels work.

posted @ Thursday, August 23, 2007 12:01 PM

Comments on this entry:

# WPF Image Viewer Part 5, Panels

Left by Nir's Software Company at 9/16/2007 4:39 PM

WPF Image Viewer Part 5, Panels

# WPF Image Viewer Part 6, Binding to Current List Item

Left by Nir's Software Company at 9/18/2007 11:26 AM

WPF Image Viewer Part 6, Binding to Current List Item

# WPF Image Viewer Part 7, Rotating the Image with a Transform and More Data Binding Between Controls

Left by Nir's Software Company at 11/15/2007 5:27 PM

WPF Image Viewer Part 7, Rotating the Image with a Transform and More Data Binding Between Controls

# re: WPF Image Viewer Part 4, Data Templates and Resources

Left by suemax at 5/7/2010 9:23 PM

AWESOME article! Very clear, concise explanations, and a great example!

# re: WPF Image Viewer Part 4, Data Templates and Resources

Left by Bagshot at 4/21/2011 1:19 PM

Without doubt one of the best tutorials on the internet. I've been searching for days for something like this. Really good job!

Your comment:



 (will not be displayed)


 
 
Please add 1 and 5 and type the answer here: