Databinding the videogame, part 6: logical coordinates

Last time I made my map 2-D. However, the coordinates left something to be desired.

The way I left the code last time, if I wanted to put two SteelPlates next to one another, I would need code like this:

var steelPlate = new SteelPlate();
m_map.Add(new Square(steelPlate, 0, 0));
m_map.Add(new Square(steelPlate, 40, 0));

That’s a problem. In the GUI, each square happens to be 40 pixels by 40 pixels. But that 40-pixel thing is strictly a GUI matter. The map, and the Square class, are DataModel objects that should have no GUI awareness, and that includes GUI constants.

Instead, I want to be able to write this:

var steelPlate = new SteelPlate();
m_map.Add(new Square(steelPlate, 0, 0));
m_map.Add(new Square(steelPlate, 1, 0));

That is, I want Square.X and Square.Y to be in logical coordinates, not in pixel coordinates. Then onscreen, the 1 should magically become 40 so that everything looks right.

This is certainly doable — in fact, there are several possible ways of dealing with it. Here are the most plausible ones I can think of:

  1. Scale transforms. This is a possibility, but not an easy one. I’d love to design all my terrain views to be 1×1 pixels, and then scale them up for display, but Visual Studio’s WPF designer maxes out at 20x zoom. Designing my tiles at no better than 20×20 pixels in the designer, when they’ll be at least 40×40 at runtime, feels way too cramped. I could always design them at 40×40, scale them down to 1×1 inside the MapView, and then scale the MapView back up, but that feels way too silly.
  2. ViewModel collection. I thought about making a ViewModel, and explicitly binding the GUI to the ViewModel instead of directly to the DataModel. That seems like a great idea — except that I’m dealing with a collection, which makes it more complicated. The back-end logic will need a collection of simple DataModel objects, so it can do things like collision detection; then the GUI would need to bind to a parallel collection of ViewModels; and both collections need to be kept in sync in the face of changes. It’s possible to make an observable collection that wraps and adapts another observable collection, but that’s an awful lot of work.
  3. On-demand ViewModels. I would love to be able to use the same ViewModel as in #2, but manufacture the ViewModels on the fly as needed. This would be great if it worked, but I haven’t been able to figure out how to do it. I can easily add another DataTemplate to map a Square to a SquareViewModel, but that puts the SquareViewModel nested inside another child control — i.e., it moves down the visual tree. It doesn’t do anything to make the ViewModel’s X and Y available at the top level, which is where I actually have to bind to Canvas.Left and Canvas.Top using ItemContainerStyle. Much as I would love to do this one, it looks like a non-starter based on what I know about WPF.
  4. ValueConverters. I could continue to bind the view directly to the DataModel, and use a custom ValueConverter to scale the X and Y values that get databound.

Option #4 is the simplest to implement. #2 would have the benefit of giving me a ViewModel class that I can unit-test, but first I would have to build a dynamic collection decorator and unit-test that thoroughly to make sure I’m actually getting the right ViewModel at the right time.

I’m going to go with simplicity for now, and do #4. If it later turns out not to be good enough, I’ll probably switch to #2.

CoordinateConverter

So I need a CoordinateConverter class:

public class CoordinateConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
        CultureInfo culture)
    {
        return ((int)value) * 40;
    }
    public object ConvertBack(object value, Type targetType, object parameter,
        CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

I only need a one-way binding: I’ll only ever propagate the DataModel value to the GUI; I’ll never change the GUI’s Canvas.Left and expect that to propagate back down to the DataModel. So I don’t need ConvertBack.

Then I put a CoordinateConverter instance into MapView‘s Resources, and reference it from the X and Y Bindings:

@@ -3,8 +3,10 @@
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:TerrainDataModels="clr-namespace:Game.Core.TerrainDataModels"
     xmlns:TerrainViews="clr-namespace:Game.Core.TerrainViews"
+    xmlns:GameViews="clr-namespace:Game.Core.GameViews"
     MinWidth="40" MinHeight="40" Background="Gray">
     <UserControl.Resources>
+        <GameViews:CoordinateConverter x:Key="CoordinateConverter"/>
         <DataTemplate DataType="{x:Type TerrainDataModels:Square}">
             <ContentPresenter Content="{Binding Path=Terrain}"/>
         </DataTemplate>
@@ -23,8 +25,8 @@
         </ItemsControl.ItemsPanel>
         <ItemsControl.ItemContainerStyle>
             <Style>
-                <Setter Property="Canvas.Left" Value="{Binding Path=X}"/>
-                <Setter Property="Canvas.Top" Value="{Binding Path=Y}"/>
+                <Setter Property="Canvas.Left" Value="{Binding Path=X,
+                    Converter={StaticResource CoordinateConverter}}"/>
+                <Setter Property="Canvas.Top" Value="{Binding Path=Y,
+                    Converter={StaticResource CoordinateConverter}}"/>
             </Style>
         </ItemsControl.ItemContainerStyle>
     </ItemsControl>

The only other detail is tweaking the random-number code in Window1 so that the now-logical coordinates will actually fit into the window:

@@ -21,8 +21,8 @@
         private void AddTerrain(Terrain terrain)
         {
             var random = new Random();
-            var x = random.Next(200);
-            var y = random.Next(200);
+            var x = random.Next(5);
+            var y = random.Next(5);
             m_map.Add(new Square(terrain, x, y));
         }
         private void Dirt_Click(object sender, RoutedEventArgs e)

databindingthevideogamepart6

Today’s test project

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/part6

What’s next?

There’s obviously some work that needs to be done around encapsulation and map generation, but I think I want to get more of the GUI working before I delve into logic too deeply.

As far as GUI work, map rendering is pretty much done, but I haven’t touched scrolling yet. I already said I won’t have scrollbars, but I’ll still have scrolling; it’ll just be automatic instead of scrollbar-controlled. My map will be bigger than the screen, and the player will move through it. But before I add scrolling, I need a reason for it to scroll — namely, because the player is moving around in it.

So I think it’s about time I make a little guy who can walk around the screen. Stay tuned.

ReSharper coolness of the day: TODOs and NotImplementedException

ReSharper adds much fancier syntax highlighting to Visual Studio. And I recently found an unexpected coolness in how they highlight TODOs.

TODO highlighting

One of the things ReSharper adds is highlighting of TODO comments. By default they’re bold and bright blue (as opposed to the non-bold green of regular comments), making them stand out nicely.

They also have a “To-do Explorer” window that lists all the TODO items in your solution.

NotImplementedException vs. NotSupportedException

Okay, it’s going to feel like I’m shifting gears for a minute here.

The .NET framework includes two exceptions that mean very nearly the same thing: NotImplementedException and NotSupportedException. I always used to have to stop and think about the difference between them, and which one I really wanted, every time I wrote — or read — code that used them.

Just for reference, here’s what they mean:

  • NotImplementedException: Placeholder. Often inserted by a code template. This means that the real code hasn’t been written yet. It’s basically a TODO with teeth.
  • NotSupportedException: Means “this space intentionally left blank”. We made a conscious decision here. This class does not and will not support this method. For example, an interface method that isn’t applicable for a given implementation.

Two great things that taste great together

In ReSharper 4.5, the following code will, under the default settings, highlight blue and bold, just like a TODO comment:

throw new NotImplementedException();

So with ReSharper, I don’t need to stop and think about the difference between NotImplementedException and NotSupportedException. They make it dead simple: if it highlights like a TODO comment, then it’s the one that really means TODO.

As I so often say when I’m talking about ReSharper: Sweet.

Databinding the videogame, part 5: making the map 2-D

Last 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 its own Terrain.

Enter the Square

I thought about adding X and Y properties to Terrain, but that felt wrong for a lot of reasons. For one thing, it’s awkward to talk about having a Dirt terrain here and another Dirt terrain right next to it. It just doesn’t sound right: the English word “terrain” refers to a general set of characteristics, not a specific location. It also introduced some duplication into the code that I didn’t like, both in the Terrain classes and in the construction logic. And the “Terrain has X and Y” pattern would have made it hard for a spot on the map to change its terrain type at runtime, which is a feature I want to add later.

So instead, I came up with a scheme that feels “right”: the map is a collection of Squares. Each Square has a location and a Terrain.

public class Square
{
    public Square(Terrain terrain, int x, int y)
    {
        Terrain = terrain;
        X = x;
        Y = y;
    }
 
    public Terrain Terrain { get; private set; }
    public int X { get; private set; }
    public int Y { get; private set; }
}

I also considered using a Dictionary<Point, Terrain>, rather than an ObservableCollection<Square>. I went with the flat list of Squares for pragmatic reasons: it’s a lot easier to set up dynamic databinding to a flat ObservableCollection<T> than to a Dictionary.

It was pretty straightforward to change Window1‘s test buttons to add Squares to the map, instead of Terrains. Since this is still just a test project, I made it assign a random X and Y to each square it adds, each in the range 0..199.

+using System;
 using System.Collections.ObjectModel;
 using System.Windows;
 using Game.Core.TerrainDataModels;
 
 namespace DatabindingTheVideogame
 {
     /// <summary>
     /// Interaction logic for Window1.xaml
     /// </summary>
     public partial class Window1
     {
-        private readonly ObservableCollection<Terrain> m_map =
-            new ObservableCollection<Terrain>();
+        private readonly ObservableCollection<Square> m_map =
+            new ObservableCollection<Square>();
 
         public Window1()
         {
             InitializeComponent();
             mapView.DataContext = m_map;
         }
 
+        private void AddTerrain(Terrain terrain)
+        {
+            var random = new Random();
+            var x = random.Next(200);
+            var y = random.Next(200);
+            m_map.Add(new Square(terrain, x, y));
+        }
         private void Dirt_Click(object sender, RoutedEventArgs e)
         {
-            m_map.Add(new Dirt());
+            AddTerrain(new Dirt());
         }
         private void SteelPlate_Click(object sender, RoutedEventArgs e)
         {
-            m_map.Add(new SteelPlate());
+            AddTerrain(new SteelPlate());
         }
     }
 }

With these changes, the program is broken. The MapView doesn’t yet know how to bind to Squares, so if you run it now and click the buttons a few times, all you get are lines of text saying “Game.Core.TerrainModels.Square”. Let’s tackle that first, and get back to working code before we go for the new feature of 2-D.

Picking a DataTemplate based on a property

Square really has nothing to say about which GUI control to instantiate. That’s all up to the Terrain. But the GUI is bound to a collection of Squares, so it’s going to be asking the Square what it wants to put on the screen. The Square’s answer is really just going to be, “Geez, man, don’t ask me. Talk to the Terrain.”

Having a collection of X, but wanting to render X.Y, seems like it should be a common enough thing that WPF would have a built-in way to do it. And indeed it does, but only sort of. ItemsControl has a DisplayMemberPath property that sounds like just the ticket. Unfortunately it’s both poorly named and poorly documented. It seems that it’s really more of a DisplayStringMemberPath, because it renders a TextBlock with the member’s value converted to a string (a fact not clear from the docs). It ignores DataTemplates and always renders text.

So if I want MapView to render a sub-property, while still actually using DataTemplates, I have to do it myself. It’s not hard, though; I just add a DataTemplate for Square, give it a ContentPresenter, and bind the Content property:

@@ -5,6 +5,9 @@
     xmlns:TerrainViews="clr-namespace:Game.Core.TerrainViews"
     MinWidth="40" MinHeight="40" Background="Gray">
     <UserControl.Resources>
+        <DataTemplate DataType="{x:Type TerrainDataModels:Square}">
+            <ContentPresenter Content="{Binding Path=Terrain}"/>
+        </DataTemplate>
         <DataTemplate DataType="{x:Type TerrainDataModels:Dirt}">
             <TerrainViews:DirtView/>
         </DataTemplate>

This brings things back to where they were last time: clicking one of the buttons adds a new Terrain to the bottom of the column.

Now to go 2-D.

Taking it to the second dimension

There are two parts to showing the terrains in two dimensions: specifying which Panel type to use, and binding the attached properties to set the position.

By default, ItemsControl renders its children using a StackPanel, which gives us the top-to-bottom column we’ve seen so far. To go two-dimensional, we need a different type of panel. Grid would be a possibility, but to make that work you really need to predefine all your rows and columns, which sounds like a pain. So I went with Canvas: the ultimate in free-form.

To tell the ItemsControl to use a different Panel type, you set its ItemsPanelTemplate:

<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <Canvas/>
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

Then you need to bind each Square’s X and Y to something. You can’t do this in the Square’s DataTemplate, because, as far as I can tell, the Left and Top properties can only be set on immediate children of the Canvas. DataTemplate is not added as an immediate child of the Canvas; instead each item gets an ItemContainer (which is added as the immediate child of the Canvas), and then the DataTemplate goes inside the ItemContainer. So the Left and Top need to be set on the ItemContainer, which is done using an ItemContainerStyle:

<ItemsControl.ItemContainerStyle>
    <Style>
        <Setter Property="Canvas.Left" Value="{Binding Path=X}"/>
        <Setter Property="Canvas.Top" Value="{Binding Path=Y}"/>
    </Style>
</ItemsControl.ItemContainerStyle>

Honestly, I don’t fully understand why this needs a Style with Setters, rather than the same straightforward DataTemplate that’s so useful everywhere else. This is just one of those dark corners of WPF that I figure I’ll learn more about eventually, so I won’t bust my brain figuring it out now. It works, and that’s the important thing.

databindingthevideogamepart5

And there you go: a two-dimensional map. If you make these changes and run, then every time you click “Dirt” or “Steel Plate”, a new square gets added at a random position within the MapView. All it takes to make a real map is to use something more interesting than Random.Next() for the X and Y.

Today’s test project

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/part5

What’s next?

Right now, squares’ X and Y properties are in pixel coordinates, not logical coordinates. Among other things, that means the squares aren’t square with each other. I could just hack the random number generation, but I’ll do better: next time I’ll introduce coordinate systems.

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.

MapView.xaml:

@@ -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>

Window1.xaml.cs:

@@ -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.

databindingthevideogamepart4

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.

Databinding the videogame, part 3: actual databinding

Last time, I mapped terrain objects to pretty pictures — but only one terrain square at a time. And despite the title, it wasn’t really databinding as such.

This time, I fix one of those two problems… the databinding one. ’Cause it turns out it’s not hard — I just needed to figure out the right way to do it. And of course, I figured it out after I had already posted part 2.

Databinding happens through the magic of the {Binding ...} extension syntax in XAML. (Yeah, you can also do it in code, but I don’t need that today.) I already knew about some of the settings you could put between the braces; for example, {Binding Path=PropertyName} will databind to the property named PropertyName on whatever object is in the DataContext. But I couldn’t figure out how to bind my control’s Content to the DataContext itself.

Well, somehow it hadn’t occurred to me that I could just use {Binding} by itself, without any parameters inside the curly braces. But of course you can, and poof — whatever property you used {Binding} on is thenceforth bound to the DataContext, and changes whenever the DataContext changes. Once I finally figured that out, the switch to databinding was just a three-line diff (well, okay, four if you’re being picky — there was a line break):

MapView.xaml:

@@ -3,7 +3,8 @@
     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">
+    MinWidth="40" MinHeight="40" Background="Gray"
+    Content="{Binding}">
     <UserControl.Resources>
         <DataTemplate DataType="{x:Type TerrainDataModels:Dirt}">
             <TerrainViews:DirtView/>

Window1.xaml.cs:

@@ -15,11 +15,11 @@
 
         private void Dirt_Click(object sender, RoutedEventArgs e)
         {
-            mapView.Content = new Dirt();
+            mapView.DataContext = new Dirt();
         }
         private void SteelPlate_Click(object sender, RoutedEventArgs e)
         {
-            mapView.Content = new SteelPlate();
+            mapView.DataContext = new SteelPlate();
         }
     }
 }

Voilà — databinding. Of course, it still does the exact same things as before, but at least I made the title honest.

Today’s test project

Today’s project is the same as yesterday’s, but with real databinding. 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/part3

What’s next?

I’m thinking the next thing is to bind to a whole collection of terrain objects.

Yes, I know that’s what I said last time. But I’m learning this WPF stuff as I go, and on the off-chance somebody might someday stumble on this while they’re learning WPF, I think it’s worth blogging in small increments. This post is about binding a single object, which is useful info in its own right. The next one will be about binding a collection. I’m blogging in small commits.

Databinding the videogame, part 2: mapping terrain types to GUI

When I started trying to write a databound video game, my first thought was to use databinding for movement and scrolling. Which is all well and good, and I’ll cover them later. But I quickly hit on a more interesting problem (and solution).

My game needed to know which areas the hero could move through. This is a simple tile-based game, so each 40×40 map square is either passable or not. So my back-end logic needed a Map object to hold that “passability” data. It could be something as simple as a two-dimensional array of Booleans. Except that in my game, there are varying degrees of passability — for example, some terrains are passable, you just have to be moving at terminal velocity before you can crash through them. So it’s not just a Boolean; more like an enum, or, better yet, a Terrain object. So far so good.

And whenever the hero enters a new randomly-generated part of the map, I need to do two things: I need to add some new objects to this Terrain array, and I also need to add the corresponding GUI tiles on the screen.

“Aha!” thinks I. “Why should I waste ten minutes writing a simple method that adds something to two different data stores, when I could instead spend all weekend figuring out how to use an immensely complicated, nigh-impossible-to-troubleshoot databinding system that can automatically do that boring work for me?”

And so I databound the map to the GUI. And it worked. Eventually.

(If you’ve done much with WPF, this may not seem very interesting. You might even know better ways of doing it — and if so, please feel free to let me know in the comments. But I’m still learning this stuff, so I thought it was pretty cool.)

Starting small: mapping a class to a control

I won’t databind the whole map today; I’ll start with a small part — displaying one terrain square.

I’m being a good boy and writing my code in layers. The lower layer has the data model, which (for now) is just POCOs. The upper layer has the GUI. The data objects know nothing about anything GUI. So far so good — textbook stuff.

In the data model, I have classes to represent different terrains. At the moment there are only two — Dirt and SteelPlate. At the moment, they know nothing. Here are their declarations:

public class Dirt
{
}
public class SteelPlate
{
}

Not a typo. They’re both empty classes. Hey, come on, it’s only part 2 of the series.

The cool thing is, if I create an instance of this empty Dirt class, and try to show that object instance in the GUI, I don’t get a compile error, or an exception, or an empty screen, or the text “Game.Core.TerrainDataModels.Dirt”. I get a pretty picture of a square piece of dirt. (Or as close as my limited artistic ability will allow.) If I push a SteelPlate instance into the GUI, I get a pretty picture of a steel plate, with rivets in the corners and everything.

Okay, WPF doesn’t come with built-in knowledge of know to map a class called Dirt to a picture of dirt. How did I set up the mappings from those empty objects to GUI representations? Well, let’s start with this: it’s not in code. I’ll show you the only two lines of actual code I wrote in this test app (in the handlers for the “Dirt” and “Steel Plate” buttons, respectively):

mapView.Content = new Dirt();
// ...
mapView.Content = new SteelPlate();

The magic is in the way WPF can render any arbitrary object to the screen. There are a bunch of ways to tell it how to turn that POCO into a GUI control, but in this case, DataTemplate seems like the best fit. I just give it one DataTemplate that’s keyed to the Dirt class, that says “when you want to display the Dirt class on the screen, do it by creating and displaying a DirtView control”, and another one for SteelPlate that says “create and display a SteelPlateView control”. I defined a UserControl named MapView, which has the magic XAML to set up these mappings:

<UserControl x:Class="Game.Core.GameViews.MapView" ...boring XML stuff...>
    <UserControl.Resources>
        <DataTemplate DataType="{x:Type TerrainDataModels:Dirt}">
            <TerrainViews:DirtView/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type TerrainDataModels:SteelPlate}">
            <TerrainViews:SteelPlateView/>
        </DataTemplate>
    </UserControl.Resources>
</UserControl>

Then all the code has to do is add a Dirt or a SteelPlate somewhere inside a MapView, and the appropriate DirtView or SteelPlateView is created and displayed automatically.

You can see the full MapView code in MapView.xaml, but the interesting part is above — the rest of the file is XML namespace definitions, the control’s size, and its background color.

Interesting note: when I was thinking about what I wanted my classes to look like, I debated whether I should use a different class for each different type of terrain, or just have one Terrain class with an enum property. WPF decided that one for me, at least for now. It’s much easier to select a DataTemplate based on class. It’s possible to select a DataTemplate based on the value of a property, but it’s nowhere near as simple. So I’m keeping it simple.

Databinding the Videogame part 2: Sample project

Today’s test project

For today’s post, I wrote a test project with two buttons: Dirt and Steel Plate. Each button has one line of code (excerpted above) that creates a POCO and pushes it into the GUI, there to be displayed as a pretty picture. Nice and simple so far.

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/part2

What’s next?

So far, I can show a single terrain square at a time. I’m thinking the next thing is to bind to a whole collection of them, and actually show a whole map (or a subset of it) on the screen. Stay tuned.

ReSharper coolness of the day: generated constructor visibility

If you use ReSharper‘s Alt+Ins to generate a constructor, and you’re in an abstract class, ReSharper is automatically smart enough to make the constructor protected.

This only makes sense. After all, .NET design guidelines recommend that abstract classes shouldn’t have public constructors — you can’t instantiate the class, so while a public constructor is harmless, it’s also misleading.

But… no matter how much sense it makes, it’s cool. It’s one of those little details that make me like ReSharper so much.

Addendum: when you use Alt+Enter to change the constructor’s visibility, public isn’t even on the list. Nice touch.

Databinding the videogame, part 1

This weekend, I decided to take a while off from my JavaScript video game, and play around with WPF a bit.

To keep things simple, I played around with re-creating what I could remember of a game I wrote long ago for text-mode BASIC, called “The Pit”. Didn’t get too far on that goal, but it kept me from being totally aimless. And in fairly short order, not only did I have a little stick-figure guy sliding smoothly across the screen in response to left and right cursor keys, I also had him plummeting to his doom whenever he walked off a cliff. Good times.

But since I was just playing, I was hacking all the game logic into the GUI. Decent way to get a feel for things, but not sustainable. And I got tired of always having to convert my in-game coordinates (1.0 = one tile) to screen coordinates (40 “pixels” = one tile) and back, and of having to track the horizontal and vertical coordinates in totally different ways (due to the way my game’s scrolling works), and of trying to keep my data model of “which tiles are obstacles” in sync with the GUI.

So that’s when I decided I would databind my video game.

Only makes sense, doesn’t it? Keep the player’s coordinates in logical scale, maintain them in one place, and have the databinding automatically handle the multiplying by 40 and the different rules for horizontal vs vertical scrolling. Add tiles to the Map data-model object and have them automatically appear on the screen. Databind the visual effects, like automatically showing the air-friction fireball when the player starts falling too fast. And I could even write unit tests for all the game logic. (Theoretically, anyway. How do you unit-test DoubleAnimation?)

Prepare to be entertained; I know precious little about WPF. I don’t have a copy of Expression Blend, and have to make do with the mind-bogglingly awful WPF designer in Visual Studio. I can write XAML for databinding, but only barely. I have no idea how much overhead there is in WPF databinding (though honestly, it can’t possibly be slower than trying to run JavaScript in IE). I have no idea when to use StaticResource vs an inline DataTemplate inside <ItemsControl.ItemTemplate>. I get the general gist of the Model-View-ViewModel pattern, but no real clue of how to design an effective view model in practice.

But I can use WPF animation to move a stick figure across the screen. I should be good to go.

I’ve got some stuff working. Learned some things by doing them the wrong way around, getting stuck, and eventually simplifying. And now I’m going to start blogging about some of it. Stay tuned.

Continuing the browser-testing journey: more automation and Vista thumbnails

I’ve been continuing my quest to easily run my unit tests in multiple browsers. Obviously, anything that takes more than 30 seconds is worth burning a couple of weeks trying to automate.

I originally thought I could do what I wanted with a Ruby script, using Watir (for IE), FireWatir (for FireFox), and ChromeWatir (for Google Chrome). I planned to run the script on demand, e.g. from my editor’s Tools menu, to (a) launch the browsers if they weren’t already running, (b) find an existing tab that was already open to the tests, or open a new tab if needed, and (c) (re)load the test page.

Worked great — for IE. (I posted sample code last time.) But FireWatir wasn’t able to re-use existing windows/tabs. And ChromeWatir is very pre-alpha and didn’t have anywhere near the feature set I needed.

Strike the *Watirs as a solution.

So let’s step back. What steps do I really want to automate?

  1. For each browser (Chrome, FireFox, and IE):
  2. If the browser is already running, Alt+Tab to it. Otherwise, launch it.
  3. If the tests are already open, Ctrl+Tab to the correct tab. If not, Ctrl+T to open a new tab, type in the URL, and hit Enter.
  4. Press Ctrl+R (or Ctrl+Shift+R in FireFox).
  5. Watch the screen while the tests run, to see whether they all pass.

Step 2 is automatable, and so is step 4. The others pose a bit more of a problem.

Then I stumbled across a solution for step 3. All three browsers, of course, support Ctrl+Tab and Ctrl+Shift+Tab to move between open tabs. It turns out they also all support Ctrl+<tab number> to jump to a tab by position. For example, Ctrl+1 to move to the first tab. Hey, I’m running these tests in a controlled environment — I can just say that I’ll keep the tests open in the first tab in each browser!

Okay, so that takes care of 3(a), of switching to the right existing tab. What about 3(b), opening a new tab? Ah, but why should I even need to do that? When I launch the browser, I can just pass the URL on the command line. Presto — my tests open in the first tab. As long as I’m smart enough not to close that tab, I’m set.

This is looking better and better. But there’s still that pesky matter of waiting for the tests to run in each browser, before I move on to the next one.

Or is there?

See, Windows Vista has this feature where, when you hover the mouse over a taskbar button, it shows a little thumbnail of the window. And that thumbnail is live — as long as the window isn’t minimized, the thumbnail stays updated in real-time as the window repaints, even if the window is fully covered by another maximized window. And this feature has an API.

If you have a window handle, you can put a live thumbnail of that window anywhere in your application, and any size you like. You don’t even have to write timer code to keep it updated — it just happens. It’s maaaagic.

I wound up going one step better than window handles and FindWindow: I wrote code that takes the fully-qualified path to the browser EXE, and automatically finds the main window for the running process. That way, I can have one thumbnail for the 32-bit IE, and another for the 64-bit IE, even though they both use the same window class. It’s pretty slick.

I wrapped it all up into a WinForms control called WindowThumbnail. Here’s a screenshot of my app with four thumbnails: Google Chrome, FireFox, 32-bit IE, and 64-bit IE:

WindowThumbnails action shot

The code isn’t polished enough to release yet, but if you drop me a note in the contact form I can e-mail you the rough code as it stands.

I was trying to enhance this app to be able to send the Ctrl+R keystrokes to the apps — ideally without focusing the other windows — but haven’t had much luck yet (turns out some apps don’t expect to get keystrokes when they’re not the foreground window). But I’ve realized that really, I can simplify that some more. There are tools that can launch apps, change focus, send keys; I don’t need to write C# code for that. I’ve heard good things about AutoHotkey, and it looks insanely scriptable, as well as making it trivial to bind the script to a shortcut key on the keyboard.

I might well be able to get this to the point where I press one key, and my computer automatically launches the browsers, Alt+Tabs through them, sends the tab-switch and refresh keystrokes, then switches to my dashboard app where I can watch the tests scroll by on all the browser windows at once.

Man, this is what being a geek is all about.