<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	>

<channel>
	<title>Thoughts from Mirality</title>
	<atom:link href="http://lambert.geek.nz/feed/" rel="self" type="application/rss+xml" />
	<link>http://lambert.geek.nz</link>
	<description>Random thoughts and musings from Miral at Mirality Systems.</description>
	<pubDate>Wed, 24 Feb 2010 14:25:23 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Templates Galore</title>
		<link>http://lambert.geek.nz/2010/02/25/templates-galore/</link>
		<comments>http://lambert.geek.nz/2010/02/25/templates-galore/#comments</comments>
		<pubDate>Wed, 24 Feb 2010 14:25:23 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[.NET]]></category>

		<category><![CDATA[C#]]></category>

		<category><![CDATA[WPF]]></category>

		<category><![CDATA[XAML]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=75</guid>
		<description><![CDATA[(Well, look at that.  I did manage to write another Programming post after all.)
One of the really great things about WPF is its composable UI structure and dynamic layouts &#8212; the ability to replace one set of controls with another on the fly as things happen (eg. when something is selected by the user) [...]]]></description>
			<content:encoded><![CDATA[<p>(Well, look at that.  I did manage to write another Programming post after all.)</p>
<p>One of the really great things about WPF is its composable UI structure and dynamic layouts &#8212; the ability to replace one set of controls with another on the fly as things happen (eg. when something is selected by the user) and have everything adjust accordingly.  The data binding engine is one of the most important elements in this, but closely linked to it is the templating engine.</p>
<p>In this post I&#8217;ll cover a little bit of background behind DataTemplates, but the primary focus is going to be on the DataTemplateSelector &#8212; what it is, why you might want to use it, a way to make it easier to use, and finally a better alternative to using them at all.<br />
<span id="more-75"></span><br />
So, first: DataTemplates.  I&#8217;m not going to go into too much detail here (there are better references around for people who want to know more); suffice it to say that they are a means of defining a set of controls (or other UI elements, such as text or pictures) which somehow represent a particular model or presentation layer object.  Sometimes they create controls that allow the user to edit the data object (via data binding), other times they&#8217;re purely for display; often a mix of both.</p>
<p>Many controls in WPF can be linked to DataTemplates to control the display of their contents; the most commonly used is the <code>ItemTemplate</code> property of <code>ItemsControl</code> (or its descendants, such as <code>ListBox</code> and <code>ListView</code>).  And most commonly, the link is made directly, like so:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;FooTemplate&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;WrapPanel<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;TextBlock</span> <span style="color: #000066;">Text</span>=<span style="color: #ff0000;">&quot;Foo data: &quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;TextBlock</span> <span style="color: #000066;">Text</span>=<span style="color: #ff0000;">&quot;{Binding Data}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/WrapPanel<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  ...
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ListBox</span> <span style="color: #000066;">ItemsSource</span>=<span style="color: #ff0000;">&quot;{Binding FooList}&quot;</span> <span style="color: #000066;">ItemTemplate</span>=<span style="color: #ff0000;">&quot;{StaticResource FooTemplate}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></pre></div></div>

<p>This is a very basic example showing how to link a presentation control directly to a named template; it&#8217;s probably the most common type you&#8217;ll encounter in WPF code.  But this is a bit restrictive &#8212; it only lets you define one template per collection.  This is ok if your collection is uniform: it contains the same types of data and that data all needs to be rendered the same way; and of course that is indeed the most common case.  But what if you have a heterogeneous collection, containing multiple types of items?  WPF supports that too &#8212; if you don&#8217;t specify a template specifically, it will look for a template corresponding to the type of the data item:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">DataType</span>=<span style="color: #ff0000;">&quot;{x:Type app:Foo}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;WrapPanel<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;TextBlock</span> <span style="color: #000066;">Text</span>=<span style="color: #ff0000;">&quot;Foo: &quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;TextBlock</span> <span style="color: #000066;">Text</span>=<span style="color: #ff0000;">&quot;{Binding Data}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/WrapPanel<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">DataType</span>=<span style="color: #ff0000;">&quot;{x:Type app:Bar}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;WrapPanel<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;TextBlock</span> <span style="color: #000066;">Text</span>=<span style="color: #ff0000;">&quot;Bar: &quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;CheckBox</span> <span style="color: #000066;">IsChecked</span>=<span style="color: #ff0000;">&quot;{Binding State}&quot;</span> <span style="color: #000066;">Content</span>=<span style="color: #ff0000;">&quot;Active&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/WrapPanel<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  ...
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ListBox</span> <span style="color: #000066;">ItemsSource</span>=<span style="color: #ff0000;">&quot;{Binding FooList}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></pre></div></div>

<p>A useful tip to know with this technique is that WPF starts searching for templates at the container itself (in this case, the <code>ListBox</code>) and works its way out to its parents; since any control can contain resources, this means that you can define several templates for the <code>Foo</code> type, and have them chosen by context.  (It&#8217;s first to last, child to parent, and the first matching template wins, so if you want to define templates for derived classes and have a base class template as a fallback, the base class template should either be listed last in the same scope or listed in one of the parent scopes.)</p>
<p>Lists aren&#8217;t the only way to use templates, of course.  One of the most handy (and seemingly overlooked) controls is the <code>ContentPresenter</code>, which is the &#8220;basic presenter&#8221; of the template system.  You can use it wherever you have a single item of content to present:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ContentPresenter</span> <span style="color: #000066;">Content</span>=<span style="color: #ff0000;">&quot;{Binding MyFoo}&quot;</span> <span style="color: #000066;">ContentTemplate</span>=<span style="color: #ff0000;">&quot;{StaticResource FooTemplate}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></pre></div></div>

<p>And of course, it also supports the <code>DataType</code>-based lookup as well.</p>
<p>Another useful ability of the <code>ContentPresenter</code> is that it can be used to &#8220;chain&#8221; templates, which is particularly handy if you have something in common between your templates (eg. if you have a base class with two derived classes, and want to show data from all three):</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;BaseTemplate&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        ... whatever presentation you want for the base class (common to both derived classes) ...
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">DataType</span>=<span style="color: #ff0000;">&quot;{x:Type app:DerivedA}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;StackPanel<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ContentPresenter</span> <span style="color: #000066;">Content</span>=<span style="color: #ff0000;">&quot;{Binding}&quot;</span> <span style="color: #000066;">ContentTemplate</span>=<span style="color: #ff0000;">&quot;{StaticResource BaseTemplate}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        ... whatever other presentation you want for DerivedA ...
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/StackPanel<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">DataType</span>=<span style="color: #ff0000;">&quot;{x:Type app:DerivedB}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;StackPanel<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ContentPresenter</span> <span style="color: #000066;">Content</span>=<span style="color: #ff0000;">&quot;{Binding}&quot;</span> <span style="color: #000066;">ContentTemplate</span>=<span style="color: #ff0000;">&quot;{StaticResource BaseTemplate}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        ... whatever other presentation you want for DerivedB ...
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/StackPanel<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>The downside of this is that layout can&#8217;t be shared between templates, so you can&#8217;t split multiple cells of a grid between two templates (though you can contain a complete child object within one cell of the grid, as normal).</p>
<p>If you&#8217;re using it for the base class, as shown here, you have to use <code>{Binding}</code> and bind to a named template (you can&#8217;t use the type, since that&#8217;d be the derived type again and it&#8217;d get into a loop).  If you&#8217;re using it for some common member (ie. you&#8217;re specifying a binding path) then you can use either kind of lookup.</p>
<p>So, to recap thus far, we&#8217;ve seen how to locate a template by name or by the type of the data object.  But what if your requirements are more complicated?  What if some property on the object needs to define which template to use?  For example, let&#8217;s say that you have a ReadOnlyTemplate (display controls only) and an EditableTemplate (with editing controls), and you want to show one or the other depending on the ReadOnly property of the data item.</p>
<p>One way to do this is to use a <code>DataTemplateSelector</code>.  I&#8217;m not going to post a full example of this (it&#8217;s long and boring), but basically the way this works is that you have to create a new class in your code that inherits from <code>DataTemplateSelector</code>, define an instance of that class in your Resources, and then reference that on your presentation control (via <code>ItemTemplateSelector</code> for item controls or <code>ContentTemplateSelector</code> for the <code>ContentPresenter</code>, for example), instead of specifying the template directly.</p>
<p>Once you&#8217;ve done that, at runtime WPF will call the <code>SelectTemplate</code> method of your class with each data item so that you can evaluate whatever you need to in order to decide which template it should be using.  This concept is powerful, of course, but it can get tedious to write all those selector classes, especially if the decision is fairly simple (as with our ReadOnly property example).</p>
<p>So now I&#8217;m going to introduce a handy little class that should mean you&#8217;ll almost never need to write your own template selector classes again &#8212; the <a href="http://lambert.geek.nz/wpdata/wp-content/uploads/2010/02/genericdatatemplateselector.cs"><code>GenericDataTemplateSelector</code></a> (the link is to the complete source file).</p>
<p>This class is based on one I found <a href="http://ov-p.spaces.live.com/blog/cns!39D56F0C7A08D703!155.entry">here</a>; I&#8217;ve simplified some parts and added some new features.  For the most part, it will let you select between your templates with just a bit of XAML:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;ReadOnlyTemplate&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;EditableTemplate&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;BarTemplate&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;msi:GenericDataTemplateSelector</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;FooTemplates&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;msi:GenericDataTemplateSelectorItem</span> <span style="color: #000066;">Template</span>=<span style="color: #ff0000;">&quot;{StaticResource BarTemplate}&quot;</span></span>
<span style="color: #009900;">                                           <span style="color: #000066;">TemplatedType</span>=<span style="color: #ff0000;">&quot;{x:Type app:Bar}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;msi:GenericDataTemplateSelectorItem</span> <span style="color: #000066;">Template</span>=<span style="color: #ff0000;">&quot;{StaticResource EditableTemplate}&quot;</span></span>
<span style="color: #009900;">                                           <span style="color: #000066;">PropertyName</span>=<span style="color: #ff0000;">&quot;ReadOnly&quot;</span> <span style="color: #000066;">Value</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;msi:GenericDataTemplateSelectorItem</span> <span style="color: #000066;">Template</span>=<span style="color: #ff0000;">&quot;{StaticResource ReadOnlyTemplate}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/msi:GenericDataTemplateSelector<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  ...
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ListBox</span> <span style="color: #000066;">Items</span>=<span style="color: #ff0000;">&quot;{Binding FooList}&quot;</span> <span style="color: #000066;">ItemTemplateSelector</span>=<span style="color: #ff0000;">&quot;{StaticResource FooTemplates}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></pre></div></div>

<p>Essentially, you&#8217;re listing all the possible templates in turn (any number can be listed; the first one that matches the conditions will &#8220;win&#8221;).  Each selector item must have one Template and can have various conditions imposed on it; specifying no conditions will make that template always win when it is reached, so is best used as a catch-all default template at the end of the list.  Possible conditions:</p>
<table>
<tr>
<th>Condition</th>
<th>Description</th>
</tr>
<tr>
<td><code>PropertyName</code></td>
<td>Specifies the name of the property to look at on the data object.  Requires <code>Value</code>, conflicts with <code>PropertyPath</code>.</td>
</tr>
<tr>
<td><code>PropertyPath</code></td>
<td>Specifies the path (in Binding syntax) to the property to look at on the data object.  Requires <code>Value</code>, conflicts with <code>PropertyName</code>.</td>
</tr>
<tr>
<td><code>Value</code></td>
<td>Specifies the expected value of the property defined in either <code>PropertyName</code> or <code>PropertyPath</code>.</td>
</tr>
<tr>
<td><code>TemplatedType</code></td>
<td>Indicates that the data item must be (or be derived from) this type (specified with <code>{x:Type ...}</code>).</td>
</tr>
</table>
<p>If possible, you should use PropertyName over PropertyPath, as the former is more efficient.  The latter is more flexible, though, since it allows you to specify indexers and subproperties, just like in bindings.  In either case, the selector will try to convert the Value you&#8217;ve specified to the appropriate type before comparison, so you should be able to use simple strings in place of enums, bools, and other more complex types that provide conversion (such as <code>Color</code>).</p>
<p>This works best when the properties are fairly fixed &#8212; eg. any given Foo never changes between ReadOnly and editable.  This is because the template selector is only called once for any given item &#8212; if you toggle the ReadOnly property of an existing object, by default it won&#8217;t update the UI (and show/hide the editable controls).</p>
<p>If you do need to have it changing on the fly (perhaps ReadOnly has been bound to a checkbox, so the user can toggle the state, and you want it to dynamically switch between the editable and readonly templates accordingly), then there are a couple of solutions.</p>
<p>The first was mentioned on the original blog page I linked to earlier &#8212; you need to write a bit of code that gets called whenever something changes that may affect which templates need to be used:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;">  DataTemplateSelector old <span style="color: #008000;">=</span> listbox.<span style="color: #0000FF;">DataTemplateSelector</span><span style="color: #008000;">;</span>
  listbox.<span style="color: #0000FF;">DataTemplateSelector</span> <span style="color: #008000;">=</span> null<span style="color: #008000;">;</span>
  listbox.<span style="color: #0000FF;">DataTemplateSelector</span> <span style="color: #008000;">=</span> old<span style="color: #008000;">;</span></pre></div></div>

<p>&#8220;Pulsing&#8221; the selector like this will force WPF to update the templates on all of the items; it&#8217;s a bit ugly though.  Worse than that, if the presentation control is itself within a template then it&#8217;s much harder to get a reference to it from code, making this approach a lot more painful.</p>
<p>Finally, here&#8217;s an alternative to the whole DataTemplateSelector thing, using another set of WPF&#8217;s powerful features: Styles and Triggers.</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;ReadOnlyTemplate&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;EditableTemplate&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">DataType</span>=<span style="color: #ff0000;">&quot;{x:Type app:Bar}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">DataType</span>=<span style="color: #ff0000;">&quot;{x:Type app:Foo}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ContentPresenter</span> <span style="color: #000066;">Content</span>=<span style="color: #ff0000;">&quot;{Binding}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ContentPresenter.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #808080; font-style: italic;">&lt;!-- this is just to help prevent cycles; you can skip it if this</span>
<span style="color: #808080; font-style: italic;">                ContentPresenter is in a named template --&gt;</span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">DataType</span>=<span style="color: #ff0000;">&quot;{x:Type app:Foo}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ContentPresenter.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ContentPresenter.Style<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Style</span> <span style="color: #000066;">TargetType</span>=<span style="color: #ff0000;">&quot;{x:Type ContentPresenter}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Setter</span> <span style="color: #000066;">Property</span>=<span style="color: #ff0000;">&quot;ContentTemplate&quot;</span> <span style="color: #000066;">Value</span>=<span style="color: #ff0000;">&quot;{StaticResource ReadOnlyTemplate}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Style.Triggers<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
              <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTrigger</span> <span style="color: #000066;">Binding</span>=<span style="color: #ff0000;">&quot;{Binding ReadOnly}&quot;</span> <span style="color: #000066;">Value</span>=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Setter</span> <span style="color: #000066;">Property</span>=<span style="color: #ff0000;">&quot;ContentTemplate&quot;</span> <span style="color: #000066;">Value</span>=<span style="color: #ff0000;">&quot;{StaticResource EditableTemplate}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
              <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTrigger<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Style.Triggers<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
          <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Style<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ContentPresenter.Style<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ContentPresenter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  ...
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ListBox</span> <span style="color: #000066;">Items</span>=<span style="color: #ff0000;">&quot;{Binding FooList}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></pre></div></div>

<p>This is a bit more wordy than the earlier examples, of course (although some of that can be removed if you&#8217;re using named templates, which is the best option provided you don&#8217;t need to also select templates by type).  But because you&#8217;re going through the style and binding engine, WPF will be watching the ReadOnly property specifically, and will automatically switch templates if it changes (assuming that the property is observable, of course &#8212; but anything you bind to the UI should be made observable).  With this sort of responsiveness, you can do all kinds of cool things with your UI.  (The <code>ReadOnlyTemplate</code> is the default, since it appears outside of any triggers.)</p>
<p>Hopefully that all made sense to people.  Any questions?</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2010/02/25/templates-galore/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Psychonauts</title>
		<link>http://lambert.geek.nz/2010/01/27/psychonauts/</link>
		<comments>http://lambert.geek.nz/2010/01/27/psychonauts/#comments</comments>
		<pubDate>Tue, 26 Jan 2010 22:12:14 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
		
		<category><![CDATA[Games]]></category>

		<category><![CDATA[Psychonauts]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=72</guid>
		<description><![CDATA[I&#8217;ve mentioned it before, but Psychonauts is a really really good game, and absolutely everyone in the universe should get it.  (And Yahtzee agrees.)
Oh, and it&#8217;s now on sale via Steam&#8217;s Midweek Madness for US$2.  So anyone who doesn&#8217;t get it is crazy.  (Or already has it, or didn&#8217;t see it in [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://lambert.geek.nz/2008/01/11/gaming-summer/">I&#8217;ve mentioned it before</a>, but Psychonauts is a really really good game, and absolutely everyone in the universe should get it.  (<a href="http://www.escapistmagazine.com/videos/view/zero-punctuation/2-Psychonauts">And Yahtzee agrees</a>.)</p>
<p>Oh, and it&#8217;s now on sale via <a href="http://store.steampowered.com/news/3371/">Steam&#8217;s Midweek Madness for US$2</a>.  So anyone who doesn&#8217;t get it is crazy.  (Or already has it, or didn&#8217;t see it in time.)</p>
<p>And I promise I&#8217;ll make a real post sometime soon.  It&#8217;ll probably end up being another Games post though; I&#8217;m a bit out of ideas for Programming topics at the moment.</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2010/01/27/psychonauts/feed/</wfw:commentRss>
		</item>
		<item>
		<title>070809101112</title>
		<link>http://lambert.geek.nz/2009/08/07/06050403020100b/</link>
		<comments>http://lambert.geek.nz/2009/08/07/06050403020100b/#comments</comments>
		<pubDate>Thu, 06 Aug 2009 22:11:15 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
		
		<category><![CDATA[Random]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=66</guid>
		<description><![CDATA[&#8230; and now it&#8217;s 07/08/09 10:11:12, in case you happen to prefer your dates around the other way.
Ok, I&#8217;ll stop this now.  (But just so that these posts aren&#8217;t a total loss, here are some significant events on this day in history&#8230;)
I promise I&#8217;ll get around to posting something real sometime soon.  Ish.
]]></description>
			<content:encoded><![CDATA[<p>&#8230; and now it&#8217;s 07/08/09 10:11:12, in case you happen to prefer your dates around the other way.</p>
<p>Ok, I&#8217;ll stop this now.  (But just so that these posts aren&#8217;t a total loss, here are <a href="http://en.wikipedia.org/wiki/August_7">some significant events on this day in history</a>&#8230;)</p>
<p>I promise I&#8217;ll get around to posting something real sometime soon.  Ish.</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2009/08/07/06050403020100b/feed/</wfw:commentRss>
		</item>
		<item>
		<title>09080706050403020100</title>
		<link>http://lambert.geek.nz/2009/08/07/06050403020100/</link>
		<comments>http://lambert.geek.nz/2009/08/07/06050403020100/#comments</comments>
		<pubDate>Thu, 06 Aug 2009 18:05:47 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
		
		<category><![CDATA[Random]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=63</guid>
		<description><![CDATA[I don&#8217;t have anything particularly exciting to say &#8212; I just felt like posting that it is now the vaguely-numerically-significant time of 2009-08-07 06:05:04.  Woo!  
Not that anyone will notice for a long while later&#8230;  
]]></description>
			<content:encoded><![CDATA[<p>I don&#8217;t have anything particularly exciting to say &#8212; I just felt like posting that it is now the vaguely-numerically-significant time of 2009-08-07 06:05:04.  Woo! <img src='http://lambert.geek.nz/wpdata/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Not that anyone will notice for a long while later&#8230; <img src='http://lambert.geek.nz/wpdata/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2009/08/07/06050403020100/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Site Update</title>
		<link>http://lambert.geek.nz/2009/06/04/site-update/</link>
		<comments>http://lambert.geek.nz/2009/06/04/site-update/#comments</comments>
		<pubDate>Wed, 03 Jun 2009 18:04:36 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
		
		<category><![CDATA[Meta]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=59</guid>
		<description><![CDATA[As the more observant of you have probably already noticed, the site has just had a fairly major update, to both theme and the backend software.
One unfortunate side-effect of the change is that the generated wavatars will now be different (it uses a slightly different algorithm than it did before), but I don&#8217;t have too [...]]]></description>
			<content:encoded><![CDATA[<p>As the more observant of you have probably already noticed, the site has just had a fairly major update, to both theme and the backend software.</p>
<p>One unfortunate side-effect of the change is that the generated wavatars will now be different (it uses a slightly different algorithm than it did before), but I don&#8217;t have too many commenters yet so you probably haven&#8217;t grown too attached to them&#8230; <img src='http://lambert.geek.nz/wpdata/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>I&#8217;m still not entirely convinced about the layout of some of the things in the sidebars (eg. which should be on the left and which on the right), so I might still do some tweaks in the future.  But for now I&#8217;m reasonably happy with it.  Feedback is welcomed.</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2009/06/04/site-update/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Sam &amp; Max</title>
		<link>http://lambert.geek.nz/2009/05/19/sam-and-max/</link>
		<comments>http://lambert.geek.nz/2009/05/19/sam-and-max/#comments</comments>
		<pubDate>Mon, 18 May 2009 17:19:40 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
		
		<category><![CDATA[Games]]></category>

		<category><![CDATA[Sam & Max]]></category>

		<category><![CDATA[Telltale]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/2009/05/19/sam-and-max/</guid>
		<description><![CDATA[I&#8217;ve been meaning to post something about the Sam &#38; Max games for quite a while now, but never seemed to quite get around to it.  But I&#8217;ve recently been reminded of it, as I just received word of some great deals available briefly.  So let&#8217;s get the advertising spiel out of the [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been meaning to post something about the Sam &amp; Max games for quite a while now, but never seemed to quite get around to it.  But I&#8217;ve recently been reminded of it, as I just received word of some great deals available briefly.  So let&#8217;s get the advertising spiel out of the way first:</p>
<hr/>
In celebration of Telltale Games&#8217; fifth anniversary, Sam &amp; Max seasons 1 &amp; 2 (and incidentally also the new Strong Bad season) are <a href="http://store.steampowered.com/news/2501/">available at 50% discount from Steam</a> &#8212; but only until May 18th (US time) &#8212; which suggests that I probably ought to have posted this earlier, since that&#8217;s later today <img src='http://lambert.geek.nz/wpdata/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Another offer comes from Telltale themselves: if you use the coupon code <tt>EPK-9VX-3ZN-WRH</tt> at <a href="http://www.telltalegames.com/store/">their store</a> then you can get any individual episodes for US$5 instead of the regular US$9ish.  (Note that this doesn&#8217;t apply to the full-season packs though, sadly &#8212; though it does work on more than just Sam &amp; Max.)  This one lasts until June 17th (US time).</p>
<hr/>
<p>Ok, now that <em>that</em>&#8217;s out of the way, let&#8217;s move on to a discussion of the games themselves.<br />
<span id="more-53"></span></p>
<p>With the Sam &amp; Max games, Telltale essentially invented the whole episodic game concept.  Well, ok, that&#8217;s not entirely fair &#8212; other games before them (including a couple from Telltale themselves, and several from other companies) have <em>claimed</em> to be episodic &#8212; but Telltale were the first (and as far as I am aware still the <em>only</em>) company to get it really &#8220;right&#8221; on a regular basis.  (&#8221;On a regular basis&#8221; being the key thing that they&#8217;re getting right.)</p>
<p>In terms of structure, each season has consisted of five or six games released approximately one per month (<em>approximately</em>, because both seasons were released across the Christmas break, so there was a two-month gap between the first and second episodes).  They&#8217;re sold both individually and in a season bundle, priced such that the whole-season bundle is significantly cheaper than buying every episode individually.  They have, however, made two additional decisions that I believe are really good: firstly, you can buy one episode individually to try it out and see if you like it, and then upgrade to the whole season set by just paying the difference.  And secondly, if you have bought the season set then you can get it on disc as well as download for &#8220;free&#8221; (aka &#8220;cost of shipping only&#8221;).  Very user friendly.  (The download versions require online activation; the disc versions do not.  The bad news: savegames tend not to be compatible between the two either.)</p>
<p>Each episode is relatively short (two or three hours &#8212; basically <a href="http://lambert.geek.nz/2007/10/26/orange-box/">Portal</a> length), but the season as a whole adds up to a fairly decent length for an adventure game, and at a comparable price.</p>
<p>The games themselves fall smack into the adventure genre (story based, third person, inventory); controls are mouse-based point &amp; click for the most part, although each season also contains at least one &#8220;arcade&#8221; segment that is better played with the keyboard (though the mouse still works).  Each episode is complete in itself (the &#8220;mission&#8221; is introduced, pursued, and wrapped up within a single episode), and they fit together to create an overall plot that links the whole season together.  Season 2 does follow on from Season 1; though you can probably enjoy S2 by itself it does contain quite a few references to events in S1, so playing them in order is probably best.</p>
<p>The stars are of course <a href="http://en.wikipedia.org/wiki/Sam_%26_Max">Sam &amp; Max</a> themselves, probably best known from their appearance in the earlier LucasArts game <a href="http://en.wikipedia.org/wiki/Sam_%26_Max_Hit_the_Road">Sam &amp; Max Hit the Road</a> (you know, back when LucasArts games were actually <em>good</em>).  Sam is a suit-wearing anthropomorphic dog; Max is a &#8220;hyperkinetic rabbity thing&#8221;.  Both are &#8220;freelance police&#8221;; essentially private investigators who are prone to excessive displays of property damage and violence &#8212; and yet it&#8217;s all very good-natured and played (successfully) for humour.  They&#8217;re a lot of fun.</p>
<p>So, that&#8217;s probably enough of generalities.  I&#8217;m just going to post a quick synopsis of each of the episodes, and my lasting impressions of them &#8212; it&#8217;s been a fair while since I&#8217;ve played some of these, so the details are a little vague in places.</p>
<h3>Season 1</h3>
<ol>
<li><b>Culture Shock</b><br />
The duo investigate a case of hypnotism, seemingly being pushed by a group of child stars.  There&#8217;s nothing particularly spectacular that I recall about this episode, but it does provide a decent introduction to the series.</li>
<li><b>Situation Comedy</b><br />
A crazed talk-show host keeps her audience captive; it&#8217;s up to the duo to get them released.  Again, a good game but nothing spectacular.</li>
<li><b>The Mole, the Mob, and the Meatball</b><br />
Sam &amp; Max must infiltrate the Toy Mafia.  The puzzles in this one were a bit lacking (and the initial release was plagued by performance problems, although those have since been corrected) &#8212; but it did introduce the &#8220;Ted E Bear&#8221; musical number, which remains my favourite.</li>
<li><b>Abe Lincoln Must Die!</b><br />
The president has gone insane, and it&#8217;s up to Sam &amp; Max to sort him out.  Along the way, there&#8217;s another musical number (fairly gratuitous, I thought; I didn&#8217;t like it as much), Max runs for office (the horror!), and they face off against a robotic Abe Lincoln!  Much fun to be had.</li>
<li><b>Reality 2.0</b><br />
The Internet is on the blink; an aggressive virus has taken control.  In this, Sam &amp; Max actually have to enter the Internet (think VR or Tron) to fix the problem &#8212; and the whole thing finishes up with a mini text-based adventure.  This is easily my favourite episode out of the whole season.  (But then, I&#8217;m a bit of a sucker when it comes to Tron-like environments.)</li>
<li><b>Bright Side of the Moon</b><br />
A trip to the Moon (in their car, of course) leads to the final reveal and face-off with the main villain of the season (who I won&#8217;t name, to avoid spoilers).  Fairly decent, and it ties the season off nicely.  I can say that it was very satisfying to finally finish off the villain &#8212; they get <em>really</em> annoying.</li>
</ol>
<h3>Season 2</h3>
<ol>
<li><b>Ice Station Santa</b><br />
A trip into Christmas Past, Present, and Future, in order to save Christmas.  A little cliché, perhaps, but still fun.  (And yes, Christmas Future gives a bit of foreshadowing for a later episode.)  The strangely-warped Christmas toys are a particular favourite (&#8221;Torture-Me Elmer&#8221;&#8230;).</li>
<li><b>Moai Better Blues</b><br />
Easter Island and the great Moai statues.  What are they really for?  Can Sam &amp; Max win the support of not just the locals, but the gods as well?  And what is up with that volcano?</li>
<li><b>Night of the Raving Dead</b><br />
An army of zombies, led by an emo vampire.  My least favourite of the series, although I&#8217;m not entirely sure why.  (Resurrecting a Frankenstein&#8217;s-monster lookalike had some fun moments, though.)</li>
<li><b>Chariots of the Dogs</b><br />
A search for the missing Bosco&#8230; perhaps there was some truth in his crazy conspiracy theories?  My favourite in this season; the sheer amount of time-foolery is simply brilliant.</li>
<li><b>What&#8217;s New, Beelzebub</b><br />
And the series closer: the final confrontation &#8212; in Hell itself!  (And you&#8217;ve really got to see this depiction of Hell-as-corporate-wasteland.  It&#8217;s quite funny.)</li>
</ol>
<p>Supposedly Season 3 will be coming out sometime later this year.  Something to look forward to! <img src='http://lambert.geek.nz/wpdata/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2009/05/19/sam-and-max/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Steam Weekend Deal: Orange Box</title>
		<link>http://lambert.geek.nz/2009/04/26/steam-deal-orange-box/</link>
		<comments>http://lambert.geek.nz/2009/04/26/steam-deal-orange-box/#comments</comments>
		<pubDate>Sun, 26 Apr 2009 00:02:34 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
		
		<category><![CDATA[Games]]></category>

		<category><![CDATA[Half-Life]]></category>

		<category><![CDATA[Orange Box]]></category>

		<category><![CDATA[Portal]]></category>

		<category><![CDATA[Valve]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/2009/04/26/steam-deal-orange-box/</guid>
		<description><![CDATA[I&#8217;m not going to make a habit of announcing these, but this one is just too big to pass up a comment on.
As you may or may not know, for a while now Steam have been running weekend deals, wherein each weekend they will offer a game (or sometimes a game bundle) at an extreme [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m not going to make a habit of announcing these, but this one is just too big to pass up a comment on.</p>
<p>As you may or may not know, for a while now <a href="http://store.steampowered.com/">Steam</a> have been running weekend deals, wherein each weekend they will offer a game (or sometimes a game bundle) at an extreme discount (usually over 50% off).  Obviously, if you&#8217;re even remotely interested in the game being offered, these deals are hard to pass up.</p>
<p>This weekend, it&#8217;s the <a href="http://lambert.geek.nz/2007/10/26/orange-box/">Orange Box</a>.  <a href="http://store.steampowered.com/sub/469/">At 66% off.  Or US$10.</a></p>
<p>The only conceivable reason I can think of for someone to not immediately buy that (assuming of course that you didn&#8217;t miss the sale) is if you&#8217;ve already got it.  Portal alone is definitely worth it, let alone all that Half-Life goodness.</p>
<p>(Why are you still here?)</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2009/04/26/steam-deal-orange-box/feed/</wfw:commentRss>
		</item>
		<item>
		<title>StringFormatConverter</title>
		<link>http://lambert.geek.nz/2009/03/03/stringformatconverter/</link>
		<comments>http://lambert.geek.nz/2009/03/03/stringformatconverter/#comments</comments>
		<pubDate>Mon, 02 Mar 2009 15:03:01 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Rants]]></category>

		<category><![CDATA[.NET]]></category>

		<category><![CDATA[C#]]></category>

		<category><![CDATA[WPF]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/2009/03/03/stringformatconverter/</guid>
		<description><![CDATA[Today&#8217;s topic is fairly basic, but hey, it gives me a chance to moan about something weird in the framework, so it&#8217;s not all bad  
Windows Presentation Foundation.  WPF.  Essentially it&#8217;s a long-overdue reboot of the child window model coupled with a powerful data binding engine (though not without its own quirks). [...]]]></description>
			<content:encoded><![CDATA[<p>Today&#8217;s topic is fairly basic, but hey, it gives me a chance to moan about something weird in the framework, so it&#8217;s not all bad <img src='http://lambert.geek.nz/wpdata/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Windows Presentation Foundation.  WPF.  Essentially it&#8217;s a long-overdue reboot of the child window model coupled with a powerful data binding engine (though <a href="http://lambert.geek.nz/2007/10/30/wpf-multithreaded-collections/">not without its own quirks</a>).  And I love it.</p>
<p>The data binding model, though, does tend to result in the proliferation of little helper classes.  In this case, I&#8217;m referring to value converters, those classes built solely to take a property value, convert it for display purposes (usually to a string), and optionally back the other way again.<br />
<span id="more-27"></span><br />
Many of these are fairly basic, and it irritates me to have so many little &#8220;throwaway&#8221; classes that are all so similar to each other.  So here is a kind of &#8220;catch-all&#8221; converter class that I&#8217;ve built for general formatting.  It won&#8217;t completely replace the need to make custom converters on occasion, of course, but it will replace a reasonable chunk of them:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #000000;">&#91;</span>ValueConversion<span style="color: #000000;">&#40;</span><span style="color: #008000;">typeof</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">object</span><span style="color: #000000;">&#41;</span>, <span style="color: #008000;">typeof</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span>
<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">class</span> StringFormatConverter <span style="color: #008000;">:</span> IValueConverter, IMultiValueConverter
<span style="color: #000000;">&#123;</span>
  <span style="color: #0600FF;">public</span> <span style="color: #FF0000;">object</span> Convert<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">object</span> value, Type targetType, <span style="color: #FF0000;">object</span> parameter, CultureInfo culture<span style="color: #000000;">&#41;</span>
  <span style="color: #000000;">&#123;</span>
    <span style="color: #0600FF;">return</span> Convert<span style="color: #000000;">&#40;</span><span style="color: #008000;">new</span> <span style="color: #FF0000;">object</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> <span style="color: #000000;">&#123;</span> value <span style="color: #000000;">&#125;</span>, targetType, parameter, culture<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
  <span style="color: #000000;">&#125;</span>
&nbsp;
  <span style="color: #0600FF;">public</span> <span style="color: #FF0000;">object</span> ConvertBack<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">object</span> value, Type targetType, <span style="color: #FF0000;">object</span> parameter, CultureInfo culture<span style="color: #000000;">&#41;</span>
  <span style="color: #000000;">&#123;</span>
    <span style="color: #000000;">System.<span style="color: #0000FF;">Diagnostics</span></span>.<span style="color: #0000FF;">Trace</span>.<span style="color: #0000FF;">TraceError</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;StringFormatConverter: does not support TwoWay or OneWayToSource bindings.&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
    <span style="color: #0600FF;">return</span> DependencyProperty.<span style="color: #0000FF;">UnsetValue</span><span style="color: #008000;">;</span>
  <span style="color: #000000;">&#125;</span>
&nbsp;
  <span style="color: #0600FF;">public</span> <span style="color: #FF0000;">object</span> Convert<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">object</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> values, Type targetType, <span style="color: #FF0000;">object</span> parameter, CultureInfo culture<span style="color: #000000;">&#41;</span>
  <span style="color: #000000;">&#123;</span>
    <span style="color: #0600FF;">try</span>
    <span style="color: #000000;">&#123;</span>
      <span style="color: #FF0000;">string</span> format <span style="color: #008000;">=</span> <span style="color: #000000;">&#40;</span>parameter <span style="color: #008000;">==</span> <span style="color: #0600FF;">null</span><span style="color: #000000;">&#41;</span> <span style="color: #008000;">?</span> <span style="color: #0600FF;">null</span> <span style="color: #008000;">:</span> parameter.<span style="color: #0000FF;">ToString</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
      <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">String</span>.<span style="color: #0000FF;">IsNullOrEmpty</span><span style="color: #000000;">&#40;</span>format<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
      <span style="color: #000000;">&#123;</span>
        <span style="color: #000000;">System.<span style="color: #0000FF;">Text</span></span>.<span style="color: #0000FF;">StringBuilder</span> builder <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> <span style="color: #000000;">System.<span style="color: #0000FF;">Text</span></span>.<span style="color: #0000FF;">StringBuilder</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> index <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> index <span style="color: #008000;">&lt;</span> values.<span style="color: #0000FF;">Length</span><span style="color: #008000;">;</span> <span style="color: #008000;">++</span>index<span style="color: #000000;">&#41;</span>
        <span style="color: #000000;">&#123;</span>
          builder.<span style="color: #0000FF;">Append</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;{&quot;</span> <span style="color: #008000;">+</span> index <span style="color: #008000;">+</span> <span style="color: #666666;">&quot;}&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #000000;">&#125;</span>
        format <span style="color: #008000;">=</span> builder.<span style="color: #0000FF;">ToString</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
      <span style="color: #000000;">&#125;</span>
      <span style="color: #0600FF;">return</span> <span style="color: #FF0000;">String</span>.<span style="color: #0000FF;">Format</span><span style="color: #000000;">&#40;</span><span style="color: #008080; font-style: italic;">/*culture,*/</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span><span style="color: #000000;">&#41;</span>parameter, values<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
    <span style="color: #000000;">&#125;</span>
    <span style="color: #0600FF;">catch</span> <span style="color: #000000;">&#40;</span>Exception ex<span style="color: #000000;">&#41;</span>
    <span style="color: #000000;">&#123;</span>
      <span style="color: #000000;">System.<span style="color: #0000FF;">Diagnostics</span></span>.<span style="color: #0000FF;">Trace</span>.<span style="color: #0000FF;">TraceError</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;StringFormatConverter({0}): {1}&quot;</span>, parameter, ex.<span style="color: #0000FF;">Message</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
      <span style="color: #0600FF;">return</span> DependencyProperty.<span style="color: #0000FF;">UnsetValue</span><span style="color: #008000;">;</span>
    <span style="color: #000000;">&#125;</span>
  <span style="color: #000000;">&#125;</span>
&nbsp;
  <span style="color: #0600FF;">public</span> <span style="color: #FF0000;">object</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> ConvertBack<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">object</span> value, Type<span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> targetTypes, <span style="color: #FF0000;">object</span> parameter, CultureInfo culture<span style="color: #000000;">&#41;</span>
  <span style="color: #000000;">&#123;</span>
    <span style="color: #000000;">System.<span style="color: #0000FF;">Diagnostics</span></span>.<span style="color: #0000FF;">Trace</span>.<span style="color: #0000FF;">TraceError</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;StringFormatConverter: does not support TwoWay or OneWayToSource bindings.&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
    <span style="color: #0600FF;">return</span> null<span style="color: #008000;">;</span>
  <span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>The usage is fairly straightforward; simply add one to your window or application resources, and then use like so for a standard binding:</p>

<div class="wp_syntax"><div class="code"><pre class="xaml" style="font-family:monospace;">ToolTip=&quot;{Binding Path=Hostname,
    Converter={StaticResource StringFormatConverter},
    ConverterParameter=Connected to {0}}&quot;</pre></div></div>

<p>Or like this as a multi-binding:</p>

<div class="wp_syntax"><div class="code"><pre class="xaml" style="font-family:monospace;">&lt;TextBlock&gt;
  &lt;TextBlock.Text&gt;
    &lt;Binding Converter=&quot;{StaticResource StringFormatConverter}&quot;
             ConverterParameter=&quot;{}{0}: {1}&quot;&gt;
      &lt;Binding Path=&quot;When&quot; /&gt;
      &lt;Binding Path=&quot;Message&quot; /&gt;
    &lt;/Binding&gt;
  &lt;/TextBlock.Text&gt;
&lt;/TextBlock&gt;</pre></div></div>

<p>(Note that you need to use an initial <code>{}</code> escape for the multi-binding if your format string begins with a replacement placeholder.)</p>
<p>Points worth mentioning:</p>
<ul>
<li>Because this just uses <code>String.Format</code> under the covers, you can use format strings like <code>{0:s}</code> or <code>{0:##0.00}</code> if you like.</li>
<li>If you don&#8217;t specify a <code>ConverterParameter</code>, then the multi-bind converter will default to simply appending all of the values together (without any extra spacing).  (The single-bind converter will just format what you gave it, which should be equivalent to not using the converter at all.)</li>
<li>Only one-way conversion is supported (though I guess it wouldn&#8217;t be impossible to implement a two-way binding, given certain constraints).</li>
<li>I&#8217;ve tried to make it fairly robust in the face of misuse; it&#8217;ll log an error to the trace (usually only visible in the IDE, though that can be configured) if it&#8217;s used improperly, or if something throws an exception.  Either way it&#8217;ll use the previously-valid value for the binding.</li>
<li>Because <code>Binding</code> and <code>MultiBinding</code> are markup extensions, you (unfortunately) can&#8217;t bind any of their own properties.  So you can&#8217;t directly calculate the <code>ConverterParameter</code> or get it from another property, although you can get it from a static resource.  You can indirectly do it, though &#8212; you can give it a static resource object whose <code>ToString</code> returns the format you desire.</li>
</ul>
<p>And that about wraps it up, except for one final point that I&#8217;d like to have a little bit of a rant about <img src='http://lambert.geek.nz/wpdata/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<hr />
You might have noticed that in the main <code>Convert</code> method I&#8217;ve commented out the bit that passes in the <code>culture</code> parameter.  See, at first I thought this would all work similar to the <code>TypeConverter</code>s, where the culture is passed down from the calling code, if explicitly specified, or left as null if not explicitly specified.  It turns out that this is not the case for WPF, however.</p>
<p>In WPF, the <code>culture</code> parameter passed to the converter&#8217;s <code>Convert</code> method comes from the <code>ConverterCulture</code> attribute specified on the binding in the XAML, which is fair enough, and so far fairly analogous to the classic case.</p>
<p>Where things go horribly, horribly wrong, though, is that if there is no <code>ConverterCulture</code> specified against the binding in the XAML, then it defaults to the <code>lang</code> of the XAML document as a whole &#8212; and there are two really big problems with that:</p>
<ol type="a">
<li>If not specified, the document language always defaults to &#8220;<code>en-us</code>&#8220;.  This means in turn that the <code>ConverterCulture</code> will default to the US culture, which will greatly annoy those users not in the US (particularly those who don&#8217;t like US-format dates).</li>
<li>The document language is always a concrete language; if you construct a <code>Culture</code> off this (as it will do behind the scenes) then you will get the <em>defaults</em> for that culture &#8212; in particular, you will <strong>not</strong> get any customisations that the user has made in the Control Panel, which will greatly annoy those users as well.</li>
</ol>
<p>I&#8217;ve seen some code that tries to work around this problem by overriding the metadata on the language property, thereby forcing it to the root language of the current culture.  Unfortunately, while this fixes the first problem, it still suffers from the second.</p>
<p>Only by using <code>CultureInfo.CurrentCulture</code> can you get the settings that the user has customised (and thus the ones that they prefer and are expecting).  And conveniently, the standard behaviour of <code>String.Format</code> (and friends) when you pass in a <code>null</code> culture (or don&#8217;t pass it in at all) is to use the current culture settings.  So that&#8217;s really the only sensible choice.</p>
<p>Long story short: don&#8217;t use the <code>culture</code> parameter in converters unless you are definitely explicitly specifying the <code>ConverterCulture</code> in the XAML and don&#8217;t mind using fixed settings instead of what the user would normally be expecting.</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2009/03/03/stringformatconverter/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Vista Networking</title>
		<link>http://lambert.geek.nz/2009/01/16/vista-network/</link>
		<comments>http://lambert.geek.nz/2009/01/16/vista-network/#comments</comments>
		<pubDate>Thu, 15 Jan 2009 13:16:30 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
		
		<category><![CDATA[Rants]]></category>

		<category><![CDATA[network]]></category>

		<category><![CDATA[UAC]]></category>

		<category><![CDATA[Vista]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/2009/01/16/vista-network/</guid>
		<description><![CDATA[I use Vista at work (with UAC enabled; as a programmer I believe that for all the hassle UAC introduces it&#8217;s still a step in the right direction &#8212; a position that only gets reinforced when I hang around software installation forums and listen to all the sob stories from &#8220;developers&#8221; who bemoan that their [...]]]></description>
			<content:encoded><![CDATA[<p>I use Vista at work (with UAC enabled; as a programmer I believe that for all the hassle UAC introduces it&#8217;s still a step in the right direction &#8212; a position that only gets reinforced when I hang around software installation forums and listen to all the sob stories from &#8220;developers&#8221; who bemoan that their software mysteriously doesn&#8217;t work on Vista any more), as I might have mentioned before.</p>
<p>One thing about it that does seriously aggravate me though is the dumbed-down (and fundamentally broken) Network and Sharing Center.  Everything works wonderfully if you have exactly one network adaptor which acts as your gateway to the Internet &#8212; which admittedly probably covers at least 60% of the public (with most of the remainder being covered by people with one wired and one wireless connection [eg. laptops], each of which could be the gateway to the Internet, but only one at a time).</p>
<p>Stray from this model, though, and you&#8217;re in for a world of pain.  As it happens, my work PC has an extra network card (used to connect to embedded devices on a dedicated subnet, both to avoid cluttering the main network and to more easily talk to devices with fixed IPs), and it also has VMware installed, which creates two or three extra adaptors of its own.<br />
<span id="more-24"></span><br />
Vista has a fairly simple classification model for its firewall.  Each individual adaptor (or &#8220;connection&#8221;) can be specified as either Public or Private.  Public is intended for insecure locations (eg. Internet cafes or stray wireless access points), while Private is intended for secure locations (home or office LAN).  Unsurprisingly, in order to be secure by default, any new connection is considered Public by default, and if <em>any</em> connection is Public, then your computer as a whole is considered to be in a Public location and certain services are disabled.  To resolve this, you can just go into the network control panel and change the connection to Private, then you&#8217;re good to go.</p>
<p>Or are you?  The problem I&#8217;ve been having (and I&#8217;m not alone) is that Vista seems to have a very bad memory for connections that don&#8217;t actually lead to real networks (I&#8217;m not entirely sure what its criteria is, but I suspect it involves whether it can find a DHCP server on the network or not).  Because of this, it has a tendency to flip connections back to Unidentified and Public again whenever you reboot &#8212; which in turn will go disable those services that aren&#8217;t considered public-safe.  (This includes file sharing, which is very handy to have available, especially at work.)</p>
<p>Now, it is possible to change around the public profile in the firewall settings, so that the services are still available even if it does flip to public mode.  That&#8217;s not very clean, though, especially if sometimes you really do want to go Public (eg. with a wireless adaptor) and keep things secure.</p>
<p>From a bit of investigation (and Googling), I&#8217;ve discovered the following workaround to the problem.  This essentially &#8220;hides&#8221; the connections from the networking control panel &#8212; you can still see them in the Network Connections folder, but they won&#8217;t appear in the Network and Sharing Center and they won&#8217;t be considered when Vista is deciding whether the computer as a whole is Public or Private.</p>
<p>This procedure requires a regedit hack, so it&#8217;s not for the faint of heart (and don&#8217;t forget to take backups, etc etc):</p>
<ol>
<li>Run regedit.</li>
<li>Go to HKLM\SYSTEM\CurrentControlSet\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}.<br />
Under here, you&#8217;ll find a list of 0000 to 00nn (it went up to 0017 in my case; it&#8217;s likely to be different on your PC depending on how many adaptors you have).</li>
<li>Look through each of the keys in turn until you find the one that refers to the specific Adaptor that&#8217;s causing the problem.</li>
<li>Add a DWORD value called &#8220;*NdisDeviceType&#8221; (don&#8217;t forget the leading *) and give it the value 1.</li>
<li>From Network Connections, disable the adaptor, then re-enable it.</li>
<li>The adaptor should no longer be visible in the Network and Sharing Center, and (if there aren&#8217;t any more) you should be back to the Private profile.
</ol>
<p>What this will do is to tell the network discovery component that this adaptor connects directly to a single host rather than to a network, so it won&#8217;t try and look for DHCP servers (or whatever it is that it actually does) on there and go mental when it can&#8217;t find any.  It won&#8217;t affect the bit of Windows that actually lets you talk to devices on that network, though, so everything else should still work fine.</p>
<p>Note: you should only disable a connection like this if you&#8217;ve experienced this problem and if the connection is never used to connect to the Internet.  It&#8217;s strictly for secondary mini-networks.</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2009/01/16/vista-network/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Prince of Persia</title>
		<link>http://lambert.geek.nz/2009/01/13/prince-of-persia/</link>
		<comments>http://lambert.geek.nz/2009/01/13/prince-of-persia/#comments</comments>
		<pubDate>Mon, 12 Jan 2009 13:13:08 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
		
		<category><![CDATA[Games]]></category>

		<category><![CDATA[Okami]]></category>

		<category><![CDATA[Prince of Persia]]></category>

		<category><![CDATA[Xfire]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/2009/01/13/prince-of-persia/</guid>
		<description><![CDATA[One of the games that I played over the holiday period was Prince of Persia (PC, Amazon) (the 2008 one, not the 1990ish classic).
Let me get the obvious stuff out of the way first: yes, it was dumb to re-use the name; yes, it&#8217;s a &#8220;reset&#8221; of the franchise (and an attempt to start a [...]]]></description>
			<content:encoded><![CDATA[<p>One of the games that I played over the holiday period was <strong>Prince of Persia</strong> (PC, <a href="http://www.amazon.com/gp/product/B001BAU9E0?ie=UTF8&amp;tag=thougfrommira-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B001BAU9E0" target="_blank">Amazon</a><img src="http://www.assoc-amazon.com/e/ir?t=thougfrommira-20&amp;l=as2&amp;o=1&amp;a=B001BAU9E0" class="amazon-assoc" border="0" height="1" width="1" />) (the 2008 one, not the 1990ish classic).</p>
<p>Let me get the obvious stuff out of the way first: yes, it was dumb to re-use the name; yes, it&#8217;s a &#8220;reset&#8221; of the franchise (and an attempt to start a new trilogy) &#8212; which means that yes, it has new characters.</p>
<p>I didn&#8217;t actually pre-order it, but I bought it sufficiently close to the NZ release date that the pre-order packs were still available (one of the benefits of staggered release dates, I guess &#8212; since the game had already been out in the US for quite a while at that point, I had a fair idea of what to expect going into it).  The pre-order pack was fairly weak, though.  There was a mini-comic (admittedly a very nice one, though no doubt someone has scanned and uploaded it by now), a bonus content DVD (which contained a bunch of useless fluff and about six minutes worth of video &#8212; the rest of which you had to go download off the website like everyone else), and a code card to unlock some character skins for the old Sands of Time characters (which have definitely been broadcast far and wide).  What&#8217;s more, the code cards were misprinted &#8212; they have a nine-digit code, but the game only accepts eight digits.  (Fortunately, the first eight digits work.)</p>
<p>The skins are a mildly interesting touch; they&#8217;re basically just a wardrobe change (they don&#8217;t affect the facial model), but they do have a certain amusement value.  Having said that, given the choice between the standard characters and the SoT-garbed characters, my preference was definitely for the standard ones.</p>
<p>But anyway, enough about the fluff and on to the gameplay itself.<br />
<span id="more-26"></span><br />
It is, of course, a platform game at heart, requiring a fair amount of jumping skills and quick reactions.  I&#8217;ve always had an odd sort of fascination with the Prince of Persia series; while I despise timed puzzles and generally dislike precision jumping puzzles, for some reason I keep coming back to this series, which is full of both.  Of course, to date I haven&#8217;t actually <em>finished</em> any of the previous games &#8212; there&#8217;d always come a point where I got sick of falling to my death for the millionth time at a certain spot, take a break from it for a while, and just never get around to playing it again.</p>
<p>This game was different somehow.  Your sidekick Elika has the ability to rescue you from certain doom &#8212; if you&#8217;re falling to your death, she&#8217;ll grab you and drop you back on the last flat surface you had reached; if you were in combat, then she&#8217;ll pull you away from the deathblow and give you some space to recover.  It&#8217;s effectively the same as frequent quick-saves and quick-loads, checkpoints, or a rewind power (the mechanisms used in the previous games, albeit sometimes limited), but the automatic nature of it and the way it was integrated into the gameplay instead of being an out-of-game action really made it work, I think.</p>
<p>This feature has caused quite a bit of grumbling from some corners, with claims that it dumbs the game down or makes it &#8220;too easy&#8221;, or removes the sense of challenge since you can never really &#8220;fail&#8221;.  While there is some truth in this (it certainly makes the game <em>feel</em> easier), there are still plenty of opportunities for failure, whether it&#8217;s missing the mark in a wall-run and having to repeat the (sometimes lengthy) manoeuvres to try again, or nearly getting sliced in half by an enemy and retreating while they gain back some (sometimes a lot) of their health.  Consequently, there&#8217;s a feeling of success and accomplishment when you finally <em>do</em> get past a tricky section.  In the end, there really is little difference between this and a quicksave/quickload system, except that this is less disruptive to the gameplay &#8220;flow&#8221;.</p>
<p>The gameworld itself is semi-open; you&#8217;re presented with a map showing the areas that you need to explore and cleanse (more on that in a moment), and for the most part you&#8217;re free to choose the order in which to solve them.  There are some constraints, however.  The repeating theme is in fours &#8212; there are four gateway areas that require nothing special, each leading to four areas; two require one magic power to solve, two require a different power.  Once you&#8217;ve solved all four, there&#8217;s one final area in each section that requires both powers; and then the finale (once you&#8217;ve solved everything else) requires all four powers at once.  They&#8217;re arranged in a consistent pattern so that you can acquire the four powers in whatever order you like without being disadvantaged by it.</p>
<p>So, the cleansing.  The initial goal of the game is to &#8220;cleanse&#8221; each of the areas by fighting, jumping, and running your way to a special spot called the &#8220;Fertile Ground&#8221;.  Sometimes this doesn&#8217;t take much, but other times it&#8217;s quite a trek to get there (especially in the areas that the Mechanist has claimed, where there&#8217;s usually some kind of gear-based puzzle to solve).  The path is usually fairly obvious, though &#8212; most of the side paths are blocked off by the Corruption, and if you do get lost you can always ask Elika to show you where to go next (although sometimes she does get it wrong).  When you do get there, though, you&#8217;re almost always enmeshed in a fight against one of the four lieutenants of the Big Bad, which tend to escalate as you progress.  After (temporarily) defeating the bad guy, once you get Elika over to the Fertile Ground itself you&#8217;re treated to the very cool cleansing animation.  I&#8217;m admittedly a bit of a sucker for this sort of premise &#8212; and while this particular effect is nowhere near as cool as the one in <strong>Okami</strong> (<a href="http://www.amazon.com/gp/product/B000E991PC?ie=UTF8&amp;tag=thougfrommira-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B000E991PC" target="_blank">PS2</a><img src="http://www.assoc-amazon.com/e/ir?t=thougfrommira-20&amp;l=as2&amp;o=1&amp;a=B000E991PC" class="amazon-assoc" border="0" height="1" width="1" />, <a href="http://www.amazon.com/gp/product/B000Z9A95M?ie=UTF8&amp;tag=thougfrommira-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B000Z9A95M" target="_blank">Wii</a><img src="http://www.assoc-amazon.com/e/ir?t=thougfrommira-20&amp;l=as2&amp;o=1&amp;a=B000Z9A95M" class="amazon-assoc" border="0" height="1" width="1" />), it&#8217;s still pretty enjoyable.</p>
<p>After cleansing an area, you then need to traipse all over it again (now with a much more pleasant atmosphere and some additional paths opened up) to gather enough Light Seeds to take back to the temple and activate another of the powers, which will in turn let you access more areas.  (Each power unlocks four areas, with a pair of powers needed for the final area in each section and all four powers needed for the finale.)  This isn&#8217;t too complicated, though &#8212; there are 1001 Light Seeds in the game (1000 in the body of the game and 1 in the finale) and you only need about half that number to unlock all four powers.  (If you do gather all 1001 then you&#8217;re rewarded with some additional skins.  Which might not excite some people, but I quite liked them.  Also, the Jade skin you get just for completing the game [with any number of seeds] is pretty sweet, and reminds me that BG&amp;E 2 will be out soon.  Yay, I hope!)</p>
<p>A downside of the semi-open-world style is that once you get used to the basic moves (and you have to get used to them fairly quick) then the areas do get a little same-y.  Mitigating that somewhat are the powers (each of which has quite a different effect) and the way that the lieutenants introduce hazards into the areas you haven&#8217;t cleansed yet when you get too close to them, and new combat moves you have to guard against.  (Though that can be a little annoying as well.)  Also, while the mechanics (wall-run, ring-extend, grip-fall, jump, double-jump, roof-run) are fairly constant, the <em>arrangement</em> within each area is usually fairly unique and interesting (in some cases &#8212; like the two Towers &#8212; they&#8217;re deliberately similar), so while you quickly get used to (and hopefully proficient at) the moves, they never really get boring.</p>
<p>I have mixed feelings on the combat.  You only ever face one enemy at a time (whether that&#8217;s one of the lieutenants or one of the soldiers that pops up whenever you reach the midway point between two areas), and while the fights are animated reasonably well and seem suitably heroic, they can be quite frustrating at times &#8212; such as the boss you can only defeat by leading to a specific place and jumping aside at just the right moment, or when the enemies learn the gauntlet shield (where only a gauntlet attack &#8212; an extreme short range attack &#8212; will work on them; if you&#8217;re not fairly good at the block-and-counterattack manoeuvre at that point then you&#8217;re in for a world of pain).  And if you do make the wrong move then you&#8217;re treated to the <span title="Yes, this is sarcasm." style="border-bottom: 1px double red">joy</span> of a quick-time-event, where you&#8217;ll either have to hit one specific attack button (or the block button) to avoid a death-blow (and Elika save, and giving the enemy some time to recover health), or you&#8217;ll have to button-mash something (usually the sword button) like crazy &#8212; except when even that doesn&#8217;t work.  You see, <em>most</em> of the time it seems to want you to just hit the button as fast as you possibly can (and it does have to be pretty darn fast), but every once in a while it seems to decide to pulse a bit slower and will then fail you if you mash it <em>too</em> fast.  Just to keep you on your toes, I guess.  Still, no question that QTEs (or as Yahtzee calls them &#8220;press X to not die&#8221;) truly suck.</p>
<p>Speaking of Yahtzee: one of the points he made in <a href="http://www.escapistmagazine.com/videos/view/zero-punctuation/482-Prince-of-Persia" target="_blank">his review</a> referred to his dislike of the dialogue, character interactions, and the character of Elika in general.  I couldn&#8217;t disagree with that particular assessment more.  I quite enjoyed the dialogue and the glimpses it gave into the main characters and their motivations &#8212; although it was a little surprising how much Elika shared given how little the Prince reciprocated (not even his name &#8212; nor whether he really is a Prince or not; he certainly implied that he isn&#8217;t, though it&#8217;s probably still a fairly safe assumption).  The banter between them was quite amusing as well &#8212; comedy (and a certain amount of snarkiness) is definitely an underused technique in games.  I also appreciated the way that most of the sideline or &#8220;flavour&#8221; dialogue is optional &#8212; while I personally listened to all of it, I know that some people would prefer to skip the whole thing and just get on with the game.</p>
<p>There were two things in particular that I <em>didn&#8217;t</em> like about the dialogue.  One is that you had to wait for the little flashing icon to show that Elika had something more to say, and press the Talk button again &#8212; you couldn&#8217;t just hold it down to hear everything at once.  The other is that when you were near one of the puzzles the game made no distinction between Elika having some interesting bit of conversation to add (perhaps some description of the backstory, or just a bit of banter) or a (usually blatantly and pointlessly obvious) hint about the solution to the puzzle, resulting in Elika seeming to nag uselessly about the puzzle several times in a row at the end of a normal conversation about the history of the place or whatever.</p>
<p>Another thing that irritated me a bit is that while the map screen (which you can call up whenever you want) quite nicely shows your progress in cleansing the lands, the matching mosaic at the temple that it&#8217;s supposed to represent doesn&#8217;t change at all as you progress.  It also bothers me the way that Elika pronounces &#8220;Ahura&#8221;; it&#8217;s entirely possible that she&#8217;s pronouncing it correctly, but it&#8217;s certainly not the way that it sounds in <em>my</em> head. <img src='http://lambert.geek.nz/wpdata/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>The basic story is fairly straightforward; cleanse the corrupted areas, get rid of the dark lieutenants, and finally defeat the Big Bad.  Once you accomplish that, though, the finale gets a bit weird.  Something happens (which clearly came as a surprise to the Prince, though I saw it coming since about half way through), and then you&#8217;re given no choice but to <span class="spoiler">completely undo all the work you&#8217;ve accomplished in the game thus far, and (apparently) release the Big Bad (Ahriman) on the world</span>.  Of course, it all fairly screams &#8220;sequel&#8221;, so it should come as no surprise that this game is planned to be the first in a new trilogy.</p>
<p>Technical issues also cropped up; I played through the first couple of hours of the game only seeing subtitles for the main characters and not hearing any voices.  I can&#8217;t completely blame the game for that &#8212; my onboard graphics drivers are a bit flaky; they claim to support 3D sound but choke if something actually tries to use it &#8212; and the game evidently believes what it&#8217;s been told.  (Previous games I&#8217;ve played that supported 3D sound at least had a checkbox to disable it &#8212; and I <em>can</em> fault the game for not having that &#8212; but it&#8217;s still ultimately my sound card&#8217;s fault.)  I eventually managed to work around this and get the voices back by completely disabling hardware acceleration for the sound card; but that in turn led to sound effects occasionally getting &#8220;stuck&#8221; and endlessly repeating themselves (which could be interrupted relatively easily, but it also eventually caused the frame rate to suffer), which was just as irritating.</p>
<p>Overall, though, I liked it, and it&#8217;s the first Prince of Persia game that I actually finished &#8212; in fact (being of a completionist mindset), I even took the time to hunt down all 1001 Light Seeds for a 100% finish.  (According to <a href="http://www.xfire.com" target="_blank">Xfire</a>, I spent 31 hours in total playing this; though that probably includes some time with the game paused.)</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2009/01/13/prince-of-persia/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
