Stop writing INotifyPropertyChanged, start using UpdateControls

If you use MVVM, you know all about INotifyPropertyChanged, and mostly you know that it’s a pain. Simple properties are a lot of code, but otherwise not too bad; but once you start having derived properties, it’s hard to make sure you fire all the right change events at the right time (and even harder to keep it right as you refactor).

Can’t we do things the way Knockout.JS does, with a framework that automatically discovers the dependencies for you?

Why yes, yes we can. Last weekend I discovered UpdateControls.

Introduction to UpdateControls

UpdateControls is free and open-source (MIT license), is available via NuGet, and works pretty much everywhere: WinRT, WPF, Silverlight, Windows Phone 7 — even WinForms! Update: WP8 is supported too.

The idea is:

  • Don’t implement INotifyPropertyChanged on your viewmodel.
  • Wrap each of your independent variables inside an Independent<T> instance. Expose the underlying value through properties.
  • For computed properties, just write the code to compute the values.
  • Before you assign your top-level viewmodel to a DataContext, wrap it with a call to ForView.Wrap.

And that’s it. You don’t need to fire notifications manually; UpdateControls does it for you.

An example:

public class MyViewModel {
    private Independent<string> _firstName = new Independent<string>("");
    private Independent<string> _lastName = new Independent<string>("");
    private Independent<bool> _lastNameFirst = new Independent<bool>();

    // Expose independent values through simple wrapper properties:
    public string FirstName {
        get { return _firstName; }
        set { _firstName.Value = value; }
    }
    public string LastName {
        get { return _lastName; }
        set { _lastName.Value = value; }
    }
    public bool LastNameFirst {
        get { return _lastNameFirst; }
        set { _lastNameFirst.Value = value; }
    }

    // Dependent (computed) properties are just code:
    public string Name {
        get {
            if (LastNameFirst)
                return string.Format("{0}, {1}", LastName, FirstName);
            else
                return string.Format("{0} {1}", FirstName, LastName);
        }
    }
}

// And in the view:
DataContext = ForView.Wrap(new MyViewModel());

And like magic, all your properties, all your logic, will start notifying the UI of changes. Between the ForView.Wrap wrapper at the top and the Independent<T> at the bottom, UpdateControls is able to automatically track all the dependencies, and triggers change events for computed properties whenever their ingredients change. This even works if a property changes which ingredients it uses.

ForView.Wrap wraps your top-level viewmodel in an internal class called DependentObject<T>. The first time a databinding asks for a property, the DependentObject<T> switches into recording mode, and then invokes your viewmodel property. Until that property returns, the DependentObject<T> takes note of every time you read the value from any Independent<T> anywhere; and whenever you do, it hooks that Independent<T>‘s change event.

Then the DependentObject<T> caches the property value and returns. Next time XAML asks for the value, it just returns it. (Its ingredients haven’t changed, so why not?) But as soon as any of the ingredients change, it clears its cache and fires PropertyChanged. There’s a lot of magic under the covers, but using it is dead simple. In principle.

As with any magic, there are some subtleties and gotchas, which I go into below. But first, some important notes about the documentation.

API drift, or, an UpdateControls documentation survival guide

UpdateControls has a fair bit of documentation, including several good videos. Unfortunately, the API has changed in a couple of significant ways over time, but a lot of documentation still refers to the old APIs. So some places you see it one way, and some places you see it the other way, which is hella confusing.

The old APIs do still work (though not on every platform and not with every edition of Visual Studio), but there are easier — and more universal — ways to do things now.

Here are the two things you really need to know before you start reading the UpdateControls documentation:

Codegen vs. Independent<T>

Independent properties used to take more code than what I showed above. It was so tedious that the author even wrote a Visual Studio add-in to do the code generation for you. But now we have Independent<T>, which is enough simpler that you don’t need codegen. The old way still works (as long as you don’t have Visual Studio Express, which doesn’t support add-ins), but Independent<T> does a better job of encapsulating the boilerplate code, so IMO it’s the way to go.

Unfortunately, most of the code samples and screencasts still use the old way. You’ll see (and hear, in the videos) lots of references to Ctrl+D G, which tells the VS add-in to do its code generation. And you’ll see a lot of code like this:

private string _firstName;

#region Independent properties
// Generated by Update Controls --------------------------------
private Independent _indFirstName = new Independent();

public string FirstName
{
    get { _indFirstName.OnGet(); return _firstName; }
    set { _indFirstName.OnSet(); _firstName = value; }
}
// End generated code --------------------------------
#endregion

My advice: Don’t install the MSI (in these days of NuGet, the MSI is really just there to install the VS add-in). Ignore the VS add-in entirely. Tune out whenever the videos talk about Ctrl+D G.

Just add the NuGet package to your project, and then use Independent<T>. The above code becomes this, which is simple enough to write and maintain by hand:

private Independent<string> _firstName;

public string FirstName {
    get { return _firstName; }
    set { _firstName.Value = value; }
}

By the way, that’s not a typo in the getter. You can return _firstName.Value if you like, but Independent<T> also has an implicit conversion to T, so as long as it’s not Independent<object> you can indeed just return _firstName;.

{u:Update} vs. plain old bindings

Originally, UpdateControls had a XAML markup extension ({u:Update}) that you were supposed to use in place of {Binding}. It took care of turning on dependency-recording mode whenever values were bound to the UI, so that it knew how to watch for changes and update the UI when ingredients change later.

Unfortunately, not all the XAML platforms support markup extensions. Silverlight didn’t get them until v5. Windows Phone 7 doesn’t have them; not sure about 8. WinRT doesn’t support them. {u:Update} isn’t going to cut it for those platforms. I suspect that {u:Update} also wouldn’t play well with visual designers like Blend; they’re all about the {Binding}.

So UpdateControls added ForView.Wrap(), which you can use in combination with plain old {Binding}. If the objects you expose to your XAML and your DataContexts and your Bindings are wrapped for view, you get the same magic, but without needing markup extensions.

Any time you see {u:Update} in the documentation, just mentally substitute {Binding}, and make sure the viewmodel gets wrapped with ForView.Wrap before the view sees it. For example:

// Using the PersonViewModel class from the first code sample, above:
var viewModel = new PersonViewModel();
view.DataContext = ForView.Wrap(viewModel);

<!-- This will automatically update whenever ingredients (FirstName, LastName) change. -->
<TextBlock Text="{Binding Name}"/>

Gotchas

If you’re starting with UpdateControls on a new project, I would imagine it’s not too hard to follow the rules and have things work well. If you’re integrating it into an existing code base, you’re more likely to run into gotchas. Here are some of the problems I ran into when trying to refactor my project to use UpdateControls.

Don’t use INotifyPropertyChanged

If your viewmodel implements INotifyPropertyChanged, UpdateControls assumes you know what you’re doing, and ForView.Wrap won’t wrap that class; instead it presents your class as-is to the view. The consequence is that the computed-property notification magic won’t work for your INPC class or anything inside it. If you implement INotifyPropertyChanged, it’s all on you.

Which means that, if you’re trying to refactor from INPC to UpdateControls, you can’t do it one property at a time. To use Independent<T>, you can’t have INotifyPropertyChanged. You’ll have to change your entire viewmodel class at once: remove INotifyPropertyChanged, add Independent<T>s for everything, all in one fell swoop.

If you do viewmodel composition — where one viewmodel exposes other viewmodels as properties (think nested panels inside a larger screen) — then you probably want to start at the top level (the whole screen), and work toward the leaves (nested panels).

Corollary: Don’t use ObservableCollection<T>

I had viewmodels that exposed collections, and nothing was happening when the collection items’ properties changed. It turns out that ObservableCollection<T> implements INotifyPropertyChanged (makes sense when you think about it; you might want to bind to its Count) — so UpdateControls just exposed the collection instance directly to the UI, without attaching any of the dependency-recording logic: not for the collection itself, and not for the items inside it, either.

So don’t use ObservableCollection<T> with UpdateControls. Use IndependentList<T> instead (it’s the UpdateControls equivalent of an observable collection). Or just a plain old List<T> if the contents aren’t going to change. Or even a LINQ query (great for filtering — as long as the filter conditions boil down to Independent<T>, changing them will automatically re-run the LINQ query). But if you start using UpdateControls, you should get rid of all your references to ObservableCollection<T>.

ForView.Wrap and dependency properties

This one may be peculiar to my code, but I had some custom dependency properties whose value was a custom class. Once I started using UpdateControls, their value wasn’t that custom class anymore; the view layer (where dependency properties live) operates on the wrapper objects, not the actual viewmodels. Since my DependencyProperty.Register call specified that the property value should be of type MyCustomClass, but the actual instance was a DependentObject<MyCustomClass>, the bindings saw a type mismatch and never set my property. To get around this, I had to change my DependencyProperty.Register call to specify object as the property’s value type. (And of course my property’s change event had to use ForView.Unwrap<T> instead of casting directly to the class type.) This probably won’t affect many people, but it’s worth noting since I burned some time trying to figure it out.

Debugging wrapper objects

If you’re in the debugger, and you’re looking at a wrapper object (from ForView.Wrap), the tooltip will show the ToString() from the wrapped class — which is often the name of the wrapped class. It can be hard to even realize that the object you’re looking at is a wrapper, and not the viewmodel itself.

It’s not hard if you know how, though. If you expand the tooltip, wrappers will have a “HasErrors” property, and not much else. That should be easy to tell apart from your actual viewmodel (which will typically have lots of properties).

If you then want to drill down to see the properties of the wrapped instance, you can expand “Non-Public Members”, then “_wrappedObject”.

Debugger tooltip with UpdateControls

Integrating with Caliburn.Micro

I tried combining both UpdateControls and Caliburn.Micro in the same project, mostly because I was already using Caliburn.Micro’s IViewAware so my viewmodels could fire animations on the view and wait for them to complete. Here’s what I learned:

  • Don’t use Caliburn.Micro’s base viewmodel classes, because they implement INotifyPropertyChanged (see above).
  • Caliburn.Micro doesn’t know about UpdateControls’ wrapper classes. If you’re doing viewmodel-first (where Caliburn.Micro automatically discovers and instantiates the correct view type for you), and your DataContext is a DependentObject<PersonViewModel>, Caliburn.Micro’s conventions will probably look for a DependentObjectView or something — it doesn’t know that it’s supposed to look for a PersonView. This isn’t hard to deal with, though; Caliburn.Micro has good extensibility points for this sort of thing.
  • The IViewAware stuff won’t work out of the box either, because Caliburn.Micro takes the DataContext and says “does it implement IViewAware?” and of course it doesn’t, because it’s got the wrapper object, not your viewmodel. None of the lifecycle stuff (IGuardClose and the like) would work either, because it’s also based on interfaces. Again, you could hook CM’s extensibility points to make this work.
  • No idea how Caliburn.Micro’s {x:Name}-based binding conventions would play with UpdateControls. I didn’t get that far.

In the end, I decided not to use Caliburn.Micro for this app. I had a lot of custom UI, so the conventions weren’t much use to me; I was really only using CM for IViewAware, which would require some coding to integrate with UpdateControls. Easier to roll my own at that point.

But I’m confident you could use the two together. If anyone digs into this further and wants to share their code, drop me a line and I’ll either post it or link to you.

Conclusion

I’m pretty excited about UpdateControls. Yeah, I spent a lot of time here talking about the downsides and gotchas. But I wouldn’t have bothered if it didn’t show so much promise.

If you’ve used Knockout, or if you’re tired of keeping track of which calculated properties to fire PropertyChanged events for whenever something changes, you owe it to yourself to take a look at UpdateControls.

Here’s where to start:

  • First, look through the notes above about API drift. You’ll want to be able to mentally translate the out-of-date code samples as you see them.
  • Then head over to the UpdateControls documentation and read through all half-dozen or so pages; they’re short. Also take a quick look through the other sections in the sidebar (“Examples”, “Tips”, “Advanced Topics”).
  • Then check out the videos, which cover different material than the docs, and which dig a lot deeper. They’ll really give you an idea of what UpdateControls can do.

Refactoring with MVVM is easy!

I’ve built up a kind of intellectual appreciation for some of the things MVVM gives you, but today I had a real “wow!” moment.

I’ve been working on a WPF UserControl, and it was getting kind of big and cumbersome. I wanted to extract some pieces from it into smaller UserControls to make it more manageable (and to make it easier to make some changes to the high-level layout).

So I created a new UserControl, moved my XAML into it, and referenced it from the original spot.

And that was it. I ran it, and it worked. That simple. No worries about moving dozens of code-behind methods onto the new control. No messing with method and field visibilities, and figuring out which objects the new control needed to have references to so it could do its work. No re-hooking event handlers.

Okay, it wasn’t quite cut-and-paste — there was some fixup to be done. The new UserControl needed some xmlns: attributes added. And I wanted the attached layout properties (Grid.Row, Grid.Column) to stay in the original file, not move into the new one (they’re part of the parent layout, not intrinsic to the child UI). So it took maybe a minute or so.

But it was nothing like the splitting headache that is extracting a UserControl in WinForms.

And then I extracted another UserControl. And I ran. And it just worked.

Wow.

Just, wow.

But the downside is, now I’ve got this overwhelming temptation to rewrite our million-line codebase in WPF…

MVVM and DialogResult with no code-behind

I like the Model-View-ViewModel pattern in WPF, and the way it helps get code out of the UI and into a place you can test it. But every now and then you run into a weird limitation — something you can’t do out of the box. One such example is closing a dialog box.

WPF’s Button doesn’t have a DialogResult property like buttons did in Delphi and WinForms. Instead, the codebehind for your OK button has to manually set the Window’s DialogResult property to true. This makes sense in principle — it lets you validate the user input before you close — but it makes it hard to use “pure” MVVM with no code-behind. I don’t actually give a hoot about blendability (I still write all my own XAML), but since I’m still learning WPF and MVVM, I take it as a challenge to find pure-MVVM solutions to problems, just as a learning exercise.

The obvious (wrong) solution

The obvious solution would be to just do this:

<Window ...
        DialogResult="{Binding DialogResult}">

Then make your ViewModel implement INotifyPropertyChanged in the usual way, and DialogResult gets pushed up to the view the same way as everything else. Right?

Unfortunately, DialogResult isn’t a dependency property (good grief, why not?), so the above code gives you a runtime error when you try to create the window:

A ‘Binding’ cannot be set on the ‘DialogResult’ property of type ‘TestWindow’. A ‘Binding’ can only be set on a DependencyProperty of a DependencyObject.

Back to the drawing board.

Others’ solutions

Some Googling found a StackOverflow post, “how should the ViewModel close the form?”, with an accepted answer (with 5 downvotes) of “give up; you can’t use MVVM for dialog boxes”. But I’m not quite ready to throw in the towel, so I keep reading.

Another answer on the same question — which had 0 upvotes at the time I read it, despite perfectly answering the question — pointed to a blog post by Adam Mills: “Window.Close() from XAML”. Adam’s solution uses an attached behavior. I’m learning to appreciate the attached-behavior pattern; you create an attached property, but then give it side-effects. It’s a good way to get code out of the codebehind, and it forces you to make it reusable at the same time.

But I’m not crazy about the details of Adam’s solution, because it requires you to create a style, hook up triggers, …a lot of mess. His post doesn’t actually have a complete code sample, so I’m not even sure how you hook the style into your window, though I’m sure I could puzzle it out eventually. And even his incomplete example is five lines of XAML. It’d probably be up to 7 or 9 by the time you actually got it fully wired up, and that’s 7 or 9 lines that you have to repeat for every dialog box you write.

Shouldn’t it be simpler? Shouldn’t it be almost as simple as the databinding syntax would have been, if the WPF team had gotten it right and made DialogResult a dependency property?

The one-line* attached behavior

* Okay, yes, it’s two lines if you count the XML namespace.

So I rolled my own attached behavior that does make it almost that simple. Here’s how you use it:

<Window ...
        xmlns:xc="clr-namespace:ExCastle.Wpf"
        xc:DialogCloser.DialogResult="{Binding DialogResult}">

Your ViewModel should expose a property of type bool? (Nullable<bool>), and should implement INotifyPropertyChanged so it can tell the view when its value has changed.

Here’s the code for DialogCloser:

using System.Windows;
 
namespace ExCastle.Wpf
{
    public static class DialogCloser
    {
        public static readonly DependencyProperty DialogResultProperty =
            DependencyProperty.RegisterAttached(
                "DialogResult",
                typeof(bool?),
                typeof(DialogCloser),
                new PropertyMetadata(DialogResultChanged));
 
        private static void DialogResultChanged(
            DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            var window = d as Window;
            if (window != null)
                window.DialogResult = e.NewValue as bool?;
        }
        public static void SetDialogResult(Window target, bool? value)
        {
            target.SetValue(DialogResultProperty, value);
        }
    }
}

I’ve posted this as an answer on the StackOverflow question, so if you think it’s a good solution, feel free to vote it up so that others can find it more easily.

WPF oddity of the day: attached/dependency properties and breakpoints

Silverlight doesn’t have any real support for ICommand, so I wrote an attached CommandBinder.Command property. Then it wasn’t working (at least when I compiled for WPF, which is a lot easier to debug), so I tried putting breakpoints in my SetCommand and CommandChanged methods. Neither ever got hit.

It turns out that WPF’s attached-property pattern is weird: you have to declare a getter and setter method, but they don’t get called.

Here’s some sample code for an attached property, just for reference:

public class CommandBinder
{
    public static DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached(
            "Command", typeof(ICommand), typeof(CommandBinder),
            new PropertyMetadata(CommandChanged));
 
    private static void CommandChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        // do something
    }
    public static ICommand GetCommand(DependencyObject d)
    {
        return (ICommand) d.GetValue(CommandProperty);
    }
    public static void SetCommand(DependencyObject d, ICommand value)
    {
        d.SetValue(CommandProperty, value);
    }
}

You have to have a setter method; otherwise you get a compiler error. (Apparently the compiler has some logic to enforce the design pattern.) But as far as the XAML parser is concerned, the setter method is more of an attribute — it says “Yeah, I’m settable.” The XAML loader doesn’t call SetCommand; it calls SetValue directly on the target object.

I did some experimenting, and it looks like this applies to dependency properties as well. You have to declare a corresponding CLR property, or you’ll get a compiler error when you try to set the property in XAML; but the XAML loader never actually uses the property.

In both cases, your setter could actually do nothing at all, and the XAML would still set the property’s value correctly. (But then anyone who tried to set the property programmatically would be in for some head-scratching. So don’t do that.)

I had wondered, in the past, why you would pass a PropertyMetadata with a change-handler delegate, rather than just putting the on-change logic inside the SetXXX or property setter. Now I know.

(Actually, in my experimenting, I was able to get it to call the property setter. All I had to do was misspell the property name that I passed to DependencyProperty.Register. So that’s why I have to tell it the name (something else I had always wondered) — so it can do a dictionary lookup. If the dictionary lookup fails, it falls back on trusty-but-slow Reflection.)

So that explains why my SetCommand wasn’t being called. Why wasn’t CommandChanged firing either? Stupid mistake on my part — I hadn’t set the DataContext, so the binding expression failed.

WPF design flaw of the day: no initial focus

When you write a WPF app and start it up, nothing has focus.

I’d call this a bug, but Microsoft has scads of testers. Somebody had to have noticed. So I can only conclude that somebody decided, on purpose, that when you write a WPF app and run it, the user shouldn’t be able to just start typing.

This is completely unlike the other two major GUI frameworks I’ve used (Delphi VCL and Windows Forms), where the app is usable by default: you open a window, your focus is in the first control in the tab order. I was therefore rather grumpy when I found out about the WPF brokenness.

Fortunately, after some digging around in Reflector, I found a nice, general fix. Adding this to the window’s constructor:

Loaded += (sender, e) =>
    MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));

will re-enable the standard behavior: initial focus is in the first control in the tab order.

This line could easily be pulled into a base class, so that all your windows can automatically inherit this behavior.

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.

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.