Monthly Archives: October 2009

Presenting PathBuilder

Currently it is annoying to build a path with Path.Combine:

var home1 = Path.Combine(Path.Combine(Path.Combine("C", "Users"), "timvw"), "My Documents");

And here is how it can be:

var home2 = PathBuilder.Combine("C", "Users", "timvw", "My Documents");

The implementation is pretty simple:

public static class PathBuilder
{
 public static string Combine(params string[] parts)
 {
  return parts.Aggregate((l, r) => Path.Combine(l, r));
 }
}

Party for one

Inspired by Jimmy Bogard’s More missing LINQ operators i found another one:

public static IEnumerable<t> MakeEnumerable<t>(this T element)
{
 yield return element;
}

Separation of concerns: Behavior = Trigger + TriggerAction

If you look at my KeyBehavior you notice that it is doing two things: register for events so that the behavior can be triggered and handle the actual command invocation. In order to enhance reuse we can refactor this KeyBehavior in a KeyTrigger and an InvokeCommandAction. Well, we’re not going to do that, because they exist already in the silverlight sdk ;)

A shortcoming of the InvokeCommandAction is that it can only invoke commands on the FrameworkElement itself, thus we write a custom implementation that finds commands on the DataContext instead:

public class InvokeCommandAction : TriggerAction<frameworkElement>
{
 public string CommandName { get; set; }

 protected override void Invoke(object parameter)
 {
  var viewModel = AssociatedObject.DataContext;
  GetCommandAndExecuteIt(viewModel, CommandName);
 }

 void GetCommandAndExecuteIt(object viewModel, string commandName)
 {
  var command = viewModel.GetPropertyValue<icommand>(commandName);
  if(command.CanExecute(null)) command.Execute(null);
 }
}

And now we can drag this action on our design surface in Blend and select a trigger that goes with it:

choosing a keypress trigger in blend

All we have to do is choose the Key and Command to invoke:

setting properties for action in blend

In XAML this looks like:

<interactivity:Interaction.Triggers>
 <ii:KeyTrigger Key="Right">
  <inf:InvokeCommandAction CommandName="PlayerRight"/>
 </ii:KeyTrigger>
 <ii:KeyTrigger Key="Left">
  <inf:InvokeCommandAction CommandName="PlayerLeft"/>
 </ii:KeyTrigger>
 <ii:KeyTrigger Key="Up">
  <inf:InvokeCommandAction CommandName="PlayerUp"/>
 </ii:KeyTrigger>
 <ii:KeyTrigger Key="Down">
  <inf:InvokeCommandAction CommandName="PlayerDown"/>
 </ii:KeyTrigger>
</interactivity:Interaction.Triggers>

I guess this ends our exploration of the behavior features in Silverlight.

True KeyBehavior with System.Windows.Interactivity.Behavior

Yesterday i demonstrated how attached properties can be used to invoke commands on specific key presses (and releases). With the aid of System.Windows.Interactivity.Behavior we can implement a true behavior and we get an extension point to do the required cleanup.

screenshot of Blend managing a KeyBehavior

<grid>
 <interactivity:Interaction.Behaviors>
  <inf:KeyBehavior>
   <inf:KeyBehavior.DownKeyCommands>
    <inf:KeyCommandName Key="Right" CommandName="PlayerRight"  />
    <inf:KeyCommandName Key="Left" CommandName="PlayerLeft" />
    <inf:KeyCommandName Key="Up" CommandName="PlayerUp" />
    <inf:KeyCommandName Key="Down" CommandName="PlayerDown" />
   </inf:KeyBehavior.DownKeyCommands>
  </inf:KeyBehavior>
 </interactivity:Interaction.Behaviors>
 ...
</grid>

The behavior implementation is the same as yesterday, only this time we thankfully override the OnAttached and OnDetaching methods:

public class KeyBehavior : Behavior<frameworkElement>
{
 public List<keyCommandName> DownKeyCommands { get; set; }
 public List<keyCommandName> UpKeyCommands { get; set; }

 public KeyBehavior()
  : base()
 {
  DownKeyCommands = new List<keyCommandName>();
  UpKeyCommands = new List<keyCommandName>();
 }

 protected override void OnAttached()
 {
  base.OnAttached();
  SubscribeToKeyEvents();
 }

 protected override void OnDetaching()
 {
  UnsubscribeFromKeyEvents();
  base.OnDetaching();
 }

 void SubscribeToKeyEvents()
 {
  AssociatedObject.KeyDown += AssociatedObject_KeyDown;
  AssociatedObject.KeyUp += AssociatedObject_KeyUp;
 }

 void UnsubscribeFromKeyEvents()
 {
  AssociatedObject.KeyDown -= AssociatedObject_KeyDown;
  AssociatedObject.KeyUp -= AssociatedObject_KeyUp;
 }

 ...

Silverlight: leveraging attached properties to handle key events

I strongly believe that input handling is a responsability that belongs to the View. At first i simply added the following in the code-behind of my GameView:

protected override void OnKeyDown(KeyEventArgs e)
{
 base.OnKeyDown(e);

 if (e.Key == Key.Left) Model.MovePlayerLeft();
 ...
}

But i wanted to play with the cool kids so i exposed ICommand properties on my ViewModel instead and rewrote the code like this:

protected override void OnKeyDown(KeyEventArgs e)
{
 base.OnKeyDown(e);

 if (e.Key == Key.Left) Model.PlayerLeft.Execute(null);
 ...

Offcourse, designers should not have to write code at all, thus i searched for a different solution. Because there isn’t a behavior that allows me to differentiate the command based on the actual key being pressed i wrote my own KeyEvents class which allows the designer to map a key to a command. Here is an example:

 <inf:KeyEvents.Down>
  <inf:KeyCommand Key="Right" CommandName="PlayerRight"  />
  <inf:KeyCommand Key="Left" CommandName="PlayerLeft" />
  <inf:KeyCommand Key="Up" CommandName="PlayerUp" />
  <inf:KeyCommand Key="Down" CommandName="PlayerDown" />
 </inf:KeyEvents.Down>
 ...
</grid>

The down property is nothing more than an attached property:

public static readonly DependencyProperty DownProperty =
 DependencyProperty.RegisterAttached("Down", typeof(List<keyCommand>), typeof(KeyEvents), new PropertyMetadata(null, OnSetDownCallback));

A KeyCommand is a simple pair of a Key and a Command name:

public class KeyCommand
{
 public Key Key { get; set; }
 public string CommandName { get; set; }
}

The GetDown method (for the attached Down property) will instantiate a KeyBehavior class which hooks up to the element’s KeyDown and KeyUp events and uses a bit of reflection to find the commands…

public class KeyBehavior
{
 public KeyBehavior(FrameworkElement frameworkElement)
 {
  FrameworkElement = frameworkElement;
  DownKeyCommands = new List<keyCommand>();
  UpKeyCommands = new List<keyCommand>();

  frameworkElement.KeyDown += frameworkElement_KeyDown;
  frameworkElement.KeyUp += frameworkElement_KeyUp;
 }

 public FrameworkElement FrameworkElement { get; set; }
 public IList<keyCommand> DownKeyCommands { get; set; }
 public IList<keyCommand> UpKeyCommands { get; set; }

 void frameworkElement_KeyUp(object sender, KeyEventArgs e)
 {
  ExecuteCommandsForKey(e.Key, UpKeyCommands);
 }

 void frameworkElement_KeyDown(object sender, KeyEventArgs e)
 {
  ExecuteCommandsForKey(e.Key, DownKeyCommands);
 }

 void ExecuteCommandsForKey(Key key, IEnumerable<keyCommand> commands)
 {
  var commandNamesForKey = commands.Where(p => p.Key == key).Select(p => p.CommandName);
  var viewModel = FrameworkElement.DataContext;
  foreach (var command in commandNamesForKey) GetCommandAndExecuteIt(viewModel, command);
 }

 void GetCommandAndExecuteIt(object model, string name)
 {
  var command = GetCommand(model, name);
  command.Execute(null);
 }

 ICommand GetCommand(object model, string name)
 {
  return (ICommand)model.GetType().GetProperty(name).GetValue(model, null);
 }
}

The only thing that is missing is a way to unsubscribe from the events (and so you will end up with memory leaks). WeakReferences may come of use but i’ll leave that as an exercise for the reader. Many thanks go to the WPF Disciples because they inspired me to come up with this attached properties magic.

Exploring graphical programming with Blend, Visual State Manager and Behaviors

A while ago i presented the ControlStateMachine and in Silverlight this concept is implemented as the Visual State Manager.

In my sokoban implementation i have a cellview which exists out of 6 canvasses but only two of them (one for the cell type and one for the piece type) are visible at any given point in time. I have implemented this with 6 properties CanvasXVisible (with X being Player, Box, Wall, Goal, Floor and Cell) in my ViewModel but a State Machine / Manager may help clarify how the visibility of the canvasses are related. Here are the 2 visual state groups and their states that i would need for the CellView:

screenshot of visual state manager in expression blend

As you can see there is quite a lof of XAML involved to make the correct canvas visible:

 <storyboard>
  <objectAnimationUsingKeyFrames BeginTime="00:00:00"  Duration="00:00:00.0010000"
   Storyboard.TargetName="Space"  Storyboard.TargetProperty="(UIElement.Visibility)">
    <discreteObjectKeyFrame KeyTime="00:00:00">
     <discreteObjectKeyFrame.Value>
      <visibility>Visible</visibility>
     </discreteObjectKeyFrame.Value>
    </discreteObjectKeyFrame>
   </objectAnimationUsingKeyFrames>
  </storyboard>
</visualState>

For a simple modification to the Visibility property this seems like overkill but in many situations you will want to change more than this one property.

With the aid of the behaviors that come with Blend i can quickly add a couple of radio buttons, toss in some gotostate actions and end up with an interactive application:

screenshot of gotostate action properties

 <i:Interaction.Triggers>
  <i:EventTrigger EventName="Checked">
   <ic:GoToStateAction StateName="Wall1"/>
  </i:EventTrigger>
 </i:Interaction.Triggers>
</radioButton>

Feel free to try it yourself by changing the radio buttons:

Conclusion: All in all it is relatively easy to create interactive applications using Blend without writing a single line of code. Too bad that the behaviors are in an Expression assembly and don’t come with standard Silverlight. Another attention point is the maintainability of this new style of programming.

ViewModel to translate domain messages to view events

Here is an example of a ViewModel that translates domain messages to view events:

class GameViewModel : INotifyPropertyChanged, IListener<boardChanged>
{
 public event PropertyChangedEventHandler PropertyChanged = delegate { };

 public GameViewModel()
 {
  var messageBus = ServiceLocator.MessageBus;
  messageBus.Subscribe<boardChanged>(this);
 }

 void IListener<boardChanged>.Handle(BoardChanged message)
 {
  PropertyChanged("Board");
 }
}

About databinding and composite views

A couple of days ago i had a databound ItemsControl (collection of Model.Cell) which instantiated sub views (with their own viewmodel).

 <grid.Resources>
  <dataTemplate x:Key="CellTemplate">
   <views:CellView />
  </dataTemplate>
 </grid.Resources>
 <itemsControl
   ItemTemplate="{StaticResource CellTemplate}"
   ItemsSource="{Binding Cells}" />
</grid>

Because each CellViewModel needs to know which cell they manage i used the following dirty hack:

public CellView()
{
 Loaded += CellView_Loaded;
}

void CellView_Loaded(object sender, RoutedEventArgs e)
{
 DataContext = new CellViewModel(DataContext);
}

Later on that day i realised there was a much cleaner solution: Let the BoardViewModel expose a collection of ViewModels.CellViewModel instead of Model.Cell. What a relief that i don’t have to use the Loaded event hack :)

Exploring M-V-VM

A couple of years ago a collegue recommended Data Binding with Windows Forms 2.0: Programming Smart Client Data Applications with .NET and i noticed that my code started to gravitate towards an Model-View-ViewModel architecture. Due to shortcomings and painful experiences i gave up on databinding and began to use Passieve View instead.

Passive View doesn’t work (well) with smart views so i decided to give M-V-VM another because i really wanted to leverage WPF’s rich support for databinding.

The key difference between M-V-VM and Passive View is, imho, the fact that the ViewModel is unaware of the View unlike Passive View where the Presenter knows about the (simple) View.

When we test a Presenter i notice that we end up writing interaction based tests (assertions on a mocked view) and when we test a ViewModel we end up writing state-based tests instead.

Sokoban: Creating graphics with Expression Design

Earlier this morning i decided to improve the graphics the little. I launched Expression Design, created a new image, and drew each possible cell and piece in a seperate layer. With this technique i can easily preview how a “Box” on “Goal” looks like.

For each layer i simply copied the XAML from Expression Design into my Cell.xaml file. Apparently all the layers are interpreted as a Canvas and the layer name determines their x:Name which makes it pretty easy to make the correct canvasses visible. With a simple ScaleTransform i can ensure that the canvasses are sized correctly.

Here is the updated version of Sokoban: