Databinding the videogame, part 4: terrain collection
Last time, I implemented real databinding, but it was only to one Terrain object at a time. Today I’ll extend it so you can add multiple terrain objects.
Before, I was binding to my UserControl’s Content property. UserControl descends from ContentControl, and ContentControls know how to do rendering magic if you put a single object in their Content. So far so good.
I had to teach WPF how to render my (non-GUI) terrain objects, and I could probably teach it how to render a collection too. Then I could either databind to a single terrain object, or to a collection of them, and either way, it would just work. But that feels like unnecessary complexity (especially since WPF syntax doesn’t lend itself to specifying a generic type, like ObservableCollection<Terrain>, for a DataTemplate’s DataType — it’s doable but not easy). And after all, I’m trying to make a map viewer, and a map will always be a collection; so why should I bother to make it do single objects too?
So I cut over to always binding a collection. This meant adding an ItemsControl to my MapView, and databinding ItemsControl.ItemsSource instead of MapView.Content.
Then I just had to change the GUI to set DataContext to a collection, and make the buttons add to the collection, and I was done.
I made sure the collection was an ObservableCollection<T>, which automatically sends change notifications that WPF databinding knows how to listen for — so all my buttons need to do is add non-GUI objects to my non-GUI-aware collection, and the GUI magically shows more GUI.
I also finally got around to making a common base class, Terrain, and making both Dirt and SteelPlate descend from it. That way I could have an ObservableCollection<Terrain>.
The diffs
I won’t bother showing the diffs for adding the Terrain base class, but here are the interesting changes for databinding a collection.
@@ -3,8 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:TerrainDataModels="clr-namespace:Game.Core.TerrainDataModels" xmlns:TerrainViews="clr-namespace:Game.Core.TerrainViews" - MinWidth="40" MinHeight="40" Background="Gray" - Content="{Binding}"> + MinWidth="40" MinHeight="40" Background="Gray"> <UserControl.Resources> <DataTemplate DataType="{x:Type TerrainDataModels:Dirt}"> <TerrainViews:DirtView/> @@ -13,4 +12,5 @@ <TerrainViews:SteelPlateView/> </DataTemplate> </UserControl.Resources> + <ItemsControl ItemsSource="{Binding}"/> </UserControl>
@@ -1,4 +1,5 @@ +using System.Collections.ObjectModel; using System.Windows; using Game.Core.TerrainDataModels; namespace DatabindingTheVideogame @@ -8,18 +9,21 @@ /// </summary> public partial class Window1 { + private readonly ObservableCollection<Terrain> m_map = + new ObservableCollection<Terrain>(); + public Window1() { InitializeComponent(); + mapView.DataContext = m_map; } private void Dirt_Click(object sender, RoutedEventArgs e) { - mapView.DataContext = new Dirt(); + m_map.Add(new Dirt()); } private void SteelPlate_Click(object sender, RoutedEventArgs e) { - mapView.DataContext = new SteelPlate(); + m_map.Add(new SteelPlate()); } } }
Yes, the collection should really live on a model object instead of in the GUI. I’ll clean this up later, but I wanted today’s diffs to be focused on just databinding a collection.
Today’s test project
Now, instead of the “Dirt” and “Steel Plate” buttons changing the one existing terrain, they add a new terrain to the collection.
As you can see from the screenshot, this isn’t a proper map yet; the terrains aren’t in a grid, they’re in a vertical column — adding a terrain puts it at the bottom of the column. And if you get to the bottom, too bad; there’s no scrollbar. (I won’t bother adding a scrollbar, either. Once I get a proper 2D map going, my game won’t need or want a scrollbar.)
You can browse today’s code online, or check it out from my Subversion repository:
svn co http://svn.excastle.com/databinding_the_videogame/tags/part4
What’s next?
So far, my “map” is one-dimensional — just a vertical column. I think the next step will be to go 2D. Stay tuned.

April 26th, 2009 at 4:00 pm
[...] time, I added the ability to have multiple Terrain objects in my map. Today I’ll take this into 2-D, so that the map is divided into logical squares, each with [...]
April 27th, 2009 at 7:53 am
[...] Databinding the videogame, part 4: terrain collection and Databinding the videogame, part 5: making the map 2-D (Joe White) [...]