DCSIMG
February 2012 - Posts - Pavel's Blog
Sign in | Join | Help

Pavel's Blog

Pavel is a software guy that is interested in almost everything
software related... way too much for too little time

February 2012 - Posts

WPF/Silverlight Tip: Transparent Hit Testing

Published at Feb 23 2012, 08:56 AM by pavely

Hit testing is the process of finding out which elements (if any) contain a certain point (typically the location of the mouse pointer). Sometimes, however, there is a need to disregard some elements in a hit testing scenario. Consider this simple program that allows moving of circles:

image

One can grab a circle and drag it around. Here’s the MouseLeftButtonDown event handler on the containing Canvas:

  1. void OnMouseDown(object sender, MouseButtonEventArgs e) {
  2.     var shape = e.Source as Shape;
  3.     if(shape != null) {
  4.         _canvas.CaptureMouse();
  5.         _moving = true;
  6.         _current = e.GetPosition(_canvas);
  7.         _currentShape = (FrameworkElement)shape.Parent;
  8.     }
  9. }

The RoutedEventArgs.Source property is consulted, because mouse events use the bubbling strategy, and the click may have happened on the Canvas itself. This Ellipse object is contained within a one cell Grid, along with a TextBlock. That’s why the _currentShape field is set to the Ellipse’s Parent (the Grid).

The problem with the above code is that clicking the TextBlock portion fails to initiate a shape move. This is because the Source is a TextBlock, so the above code fails the cast. We can add a separate check for the TextBlock, but this is error prone and fragile. There may be a complex set of elements on top of the Ellipse that we would want to disregard.

Fortunately, this is easily achievable by setting the IsHitTestVisible property to false to everything within the Grid, except the Ellipse. Such elements become “transparent” as far as hit testing is concerned.

See the attached project for the complete source.

Open days at John Bryce Hi-Tech

Published at Feb 18 2012, 02:11 PM by pavely

John Bryce Hi-Tech is having 4 Open days (half days) on current and upcoming technologies (held at John Bryce offices in Tel Aviv). Here’s the official poster:

image

These open days are free of charge – but you must register (links in the next section):

My first session (on the 29th of this month) is an overview of Windows Azure – from a developer perspective. What is it, where to get the tools, how to get started, the web and worker roles, storage, communications and more. If you heard about Azure, but did not yet take the time to dive in – this session is for you. (Link to registration).

My second session (on March 20th) will be about parallel and asynchronous programming with .NET 4 and .NET 4.5 with and without C# 5.0. This would be a somewhat similar session to the one I gave at Microsoft offices in Ra’anana on November 23rd, 2011 (with some extensions and better jokes).(Link to registration).

I hope to see you there!

Towers of Hanoi–WPF Style (Part 2)

Published at Feb 13 2012, 10:45 PM by pavely

In the first part, we saw how to recursively solve the Towers of Hanoi problem in C#. In this post I want to show a graphic view of the solution. This is a starting position with 7 discs:

image

This is how it looks when the problem is solved:

image

In between, the discs move with animation from pole to pole, as the solution dictates. Options include speeding up the process (with the slider, very useful), pausing the animation and resetting to the initial state. Here’s something in the middle:

image

The Poles

The poles are built as thick lines, with a gradient brush. They are set inside a Canvas, so their location can be set explicitly. Resizing the window causes everything to be resized appropriately. This neat trick is achieved with one of WPF’s useful Decorators – the ViewBox. The ViewBox effectively allows creation of a custom coordinate system that makes placing objects, calculating distances and whatnot easy:

  1. <Viewbox Stretch="Fill">
  2.     <Canvas x:Name="_canvas" Background="White" Width="1200" Height="1200" >
  3.         <Line Stroke="{StaticResource poleFill}" StrokeThickness="40" X1="200" Y1="120" X2="200" Y2="1200" />
  4.         <Line Stroke="{StaticResource poleFill}" StrokeThickness="40" X1="600" Y1="120" X2="600" Y2="1200" />
  5.         <Line Stroke="{StaticResource poleFill}" StrokeThickness="40" X1="1000" Y1="120" X2="1000" Y2="1200" />
  6.     </Canvas>
  7. </Viewbox>

The ViewBox child should be set a Width and Height explicitly – this sets the coordinate system. In this case, 1200x1200 units. This means that no matter the actual Canvas size – its center point (e.g.) is always (600,600).

The Discs

Each disc is a simple user control that only adds one dependency property, Text, to allow customization of the written text on top of a rectangle. Here’s the basic XAML:

  1. <UserControl x:Class="TowersOfHanoi.DiscControl"
  2.              d:DesignHeight="300" d:DesignWidth="300" x:Name="ctl">
  3.     <UserControl.Resources>
  4.         <LinearGradientBrush x:Key="discBrush" EndPoint="0,.5" SpreadMethod="Reflect">
  5.             <GradientStop Color="DarkRed" Offset="0" />
  6.             <GradientStop Color="Red" Offset="1" />
  7.         </LinearGradientBrush>
  8.     </UserControl.Resources>
  9.     <Grid>
  10.         <Rectangle Stroke="Black" StrokeThickness="2" Fill="{StaticResource discBrush}"
  11.                    RadiusX="10" RadiusY="15" />
  12.         <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
  13.                    Text="{Binding Text, ElementName=ctl}" />
  14.     </Grid>
  15. </UserControl>

What we have is a rounded Rectangle filled with a gradient brush. On top of that sits a TextBlock with its Text property bound to the Text property exposes by the user control.

The Application

The application is built around a semi-MVVM implementation. The HanoiViewModel class implements INotifyPropertyChanged and a bunch of commands (Solve, Reset, Pause) that the main window consumes. I will not describe MVVM here in detail, as this is available in so many sources. The implementation is very basic, so don’t expect too much with that – I was focusing on the graphical aspects…

Initialization

First, the discs must be created and placed in the correct position before a solving attempt can be made. The Init method is responsible for setting things up. This is the part that creates the discs and adds them to the Canvas:

  1. double width = 250, left = 200 - width / 2, bottom = 0;
  2. _poles = new PoleInfo[3];
  3. for(int i = 0; i < _vm.Discs; i++) {
  4.     var disc = new DiscControl {
  5.         Text = (_vm.Discs - i).ToString(),
  6.         FontSize = 30,
  7.         Width = width,
  8.         Height = DiscHeight,
  9.         Foreground = Brushes.White
  10.     };
  11.     _canvas.Children.Add(disc);
  12.     Canvas.SetLeft(disc, left);
  13.     Canvas.SetBottom(disc, bottom);
  14.     width -= 10;
  15.     bottom += DiscHeight;
  16.     left += 5;
  17.     _poles[0].Add(disc);
  18. }

Within a loop over all discs, a DiscControl is created and set up with the correct properties including is Width and Height. The Width is decremented by 10 units every iteration. Then the disc is added to the Canvas and placed in the correct location, that is also adjusted accordingly before the iteration ends. The last interesting detail here is an array of PoleInfo structures, that keep track of the discs on each pole. This is necessary when an animation should start for determining the moving disc and its target location in the target pole.

Animation

The animation that’s required here is a Path based animation. That is, an animation the follows a path laid out by a PathGeometry, which is the most powerful Geometry WPF provides, and can be used to create virtually any desired set of 2D curves. In this case, it should contain a PolyLineSegment that traces a route connecting 3 points of a rectangle – from some pole to another pole.

The basic geometry and the Storyboard that uses it is defined within the Resources collection of the main window:

  1. <PathGeometry x:Key="animGeometry">
  2.     <PathFigure IsClosed="False" >
  3.         <PolyLineSegment Points="150,300 150,450 30,450" />
  4.     </PathFigure>
  5. </PathGeometry>
  6. <Storyboard x:Key="moveStoryboard" SpeedRatio="{Binding Speed}">
  7.     <DoubleAnimationUsingPath Duration="0:0:3"  
  8.             Storyboard.TargetProperty="(Canvas.Left)"
  9.             PathGeometry="{StaticResource animGeometry}" Source="X" />
  10.     <DoubleAnimationUsingPath Duration="0:0:3"
  11.             Storyboard.TargetProperty="(Canvas.Bottom)"
  12.             PathGeometry="{StaticResource animGeometry}" Source="Y"/>
  13. </Storyboard>

We have 2 animations running simultaneously, animating the Canvas.Left and Canvas.Bottom properties. The former getting the X position of the point and the latter getting the Y.

When an animation should start, the PolyLineSegment is adjusted to the correct path based on the disc to be moved:

  1. private void MakeMove(HanoiMove move) {
  2.     int from = move.From - 1, to = move.To - 1;
  3.     var disc = _movingDisc = _poles[from].Top;
  4.     var start = GetPositionInPole(disc, from);
  5.     var end = GetPositionInPole(disc, to);
  6.     var g = FindResource("animGeometry") as PathGeometry;
  7.     g.Figures[0].StartPoint = start;
  8.     // update geometry
  9.     var poly = g.Figures[0].Segments[0] as PolyLineSegment;
  10.     poly.Points[0] = new Point(start.X, 1100);
  11.     poly.Points[1] = new Point(end.X, 1100);
  12.     poly.Points[2] = end;

The GetPositionInPole helper method returns a Point that is the location of a given disc in a given pole.

Then the Storyboard.Completed event is registered with an event handler, to be notified of a finished move - to advance to the next move. Then the animation actually begins:

  1. EventHandler completed = null;
  2. completed = (s, e) => {
  3.     _animation.Completed -= completed;
  4.     if(_vm.Moves != null) {
  5.         _poles[to].Add(disc);
  6.         _poles[from].Remove();
  7.         Canvas.SetLeft(disc, Canvas.GetLeft(disc));
  8.         Canvas.SetBottom(disc, Canvas.GetBottom(disc));
  9.         // next move
  10.         if(_currentMoveEnum != null)
  11.             if(_currentMoveEnum.MoveNext())
  12.                 MakeMove(_currentMoveEnum.Current);
  13.             else {
  14.                 _vm.MovesDone();
  15.                 CommandManager.InvalidateRequerySuggested();
  16.             }
  17.  
  18.     }
  19. };
  20. _animation.Completed += completed;
  21. _vm.MakeMove();
  22. // start a controllable animation
  23. _animation.Begin(disc, true);

The event handler uses a lambda expression that is first assigned to a variable. This is necessary, because part of the handling is unregistering from that same event. The last line of the preceding code actually starts the animation. Note the true parameter there; it’s essential if pausing the animation is required (as it is in our case). If the simpler Begin method is used, no call to Storyboard.Pause would have any effect.

Since the moves are provided as IEnumerable<HanoiMove>, a simple foreach is not possible, as we cannot block after an animation begins. So, _currentMoveEnum is actually using the GetEnumerator method (when initialized) and calls MoveNext and the Current property as foreach internally does – but only after a move is complete.

The are other parts of this app that may be of interest – just browse the source code. The above explanations should make it easier to follow.

In the next (and final) part, we’ll try to port this to Silverlight running on Windows Phone 7.

Towers of Hanoi–WPF Style (part 1)

Published at Feb 11 2012, 10:43 PM by pavely

I remember many years ago (at least 15), I was learning Prolog. I used the “Turbo Prolog” package from (what was once) Borland. One of the nice examples there was a solution of the Towers of Hanoi, with a simple animation that showed the steps graphically. This was all textual graphics (today’s Console windows), but it was impressive (at least it impressed me). Prolog was used to show off its AI capabilities, which are, in fact, a recursive, backtracking engine.

No matter; we can do it in C#.

Towers of Hanoi

The story of the Towers originate from an old legend (there are various versions), but may favorite is this: a group of monks were given a task (by an ancient prophecy), to transfer 64 giant discs (with sizes starting from large at the bottom to small at the top) from one large pole to another, using a third pole as an intermediary, all while observing 2 rules:

1. Only one disc can be moved at a time.

2. Under no circumstance should a larger disc lie on top of a smaller one.

When they succeed, the world would come to an end, and the monks would be granted eternal life.

Although this may be an old legend, it’s not far off the truth. It can be shown that the minimal number of moves is 2^N –1 (2 to the Nth power minus 1) where N is the number of discs. If N=64, this results in 18,446,744,073,709,551,615 moves. Assuming the monks work at a pace of one disc per second (highly unlikely), they would still need around 585 billion years to complete the task. This is a very long time – just as a quick comparison: the age of the universe is estimated at 13.7 billion years. Now it’s obvious why it’s fair to assume the world would end by then.

Even with a million moves per second, we would still need 585 thousand years!

Still, we can use a smaller N to solve the problem in our lifetime.

Here’s a starting point (this app is developed in the second part) where N = 5:

image

A recursive solution

The Towers of Hanoi problem has a simple iterative solution (or at least is simple once you know of it…), but we’ll take the recursive solution approach.

To move N discs from pole 1 to pole 3 (using pole 2 as an intermediary):

  1. Move N-1 discs from pole 1 to pole 2 (while observing the rules)
  2. Move the remaining disc (the largest one) from pole 1 to pole 3
  3. Move N-1 discs from pole2 to pole 3

Recursively, we would end up with N=1, for which a trivial transfer can be made.

Let’s create a .NET class that solves the problem. Its output should be a set of moves. Let’s first define a move:

  1. sealed class HanoiMove {
  2.     public readonly int From;
  3.     public readonly int To;
  4.  
  5.     public HanoiMove(int from, int to) {
  6.         From = from; To = to;
  7.     }
  8.  
  9.     public override string ToString() {
  10.         return string.Format("Move {0} to {1}", From, To);
  11.     }
  12. }

A very simple class.

Now for the fun part: solving the problem. The result should be a collection of HanoiMove objects, but we don’t want to calculate everything in advance – this may take too much time and even result in OutOfMemoryException. The easiest approach is with the yield keyword. This is one of my favorites, no doubt:

  1. class HanoiTower {
  2.     public int Discs { get; private set; }
  3.  
  4.     public HanoiTower(int discs) {
  5.         Discs = discs;
  6.     }
  7.  
  8.     public IEnumerable<HanoiMove> Solve() {
  9.         return MoveDiscs(Discs, 1, 3, 2);
  10.     }
  11.  
  12.     private IEnumerable<HanoiMove> MoveDiscs(int discs, int from, int to, int via) {
  13.         if(discs == 1) {
  14.             yield return new HanoiMove(from, to);
  15.             yield break;
  16.         }
  17.         foreach(var move in MoveDiscs(discs - 1, from, via, to)) {
  18.             yield return move;
  19.         }
  20.         foreach(var move in MoveDiscs(1, from, to, 0)) {
  21.             yield return move;
  22.         }
  23.         foreach(var move in MoveDiscs(discs - 1, via, to, from)) {
  24.             yield return move;
  25.         }
  26.     }
  27. }

MoveDiscs is the key method returning an IEnumerable<HanoiMove>. Don’t you just love those yields?

Let’s run with N=4 (15 moves):

  1. var tower = new HanoiTower(4);
  2. foreach(var move in tower.Solve())
  3.     Console.WriteLine(move);

image

Not easy to visualize, right?

In the second part we’ll see how to use the preceding code in a WPF application (and maybe even Silverlight) to visualize everything.

A UniformGrid for Silverlight/Windows Phone

Published at Feb 07 2012, 10:00 PM by pavely

The UniformGrid panel in WPF has some useful features, especially as an items panel in an ItemsControl. I blogged about the usefulness of the UniformGrid here. But what about Silverlight? It has no UniformGrid, but we can create one as a custom panel. This would be usable in Silverlight for the desktop and for Windows Phone, and would be a simple enough example to show in one post.

The layout process

In WPF/Silverlight, layout is a two step process. The first step is Measure: the panel asks each child it’s hosting what size it would like to be, given the available space for the panel. The second and final step is Arrange: the panel tells every child where it’s hosted and the final size it’s given; this is not debatable. The child element has to cope.

Creating a custom panel

A custom panel is created in much the same way in Silverlight as it is in WPF. There are two methods that we must override: MeasureOverride and ArrangeOverride (yes, I know, the names suck):

  1. public class UniformGrid : Panel {
  2.     protected override Size MeasureOverride(Size availableSize) {
  3.         return base.MeasureOverride(availableSize);
  4.     }
  5.  
  6.     protected override Size ArrangeOverride(Size finalSize) {
  7.         return base.ArrangeOverride(finalSize);
  8.     }
  9. }

 

Properties

Before we get to the overriding part, let’s add some properties. We want a Rows and a Columns property, which should be simple enough. We’ll use the “propdp” Visual Studio code snippet to generate the boilerplate code for registering a dependency property and just replace UIPropertyMetadata with PropertyMetadata, as the former exists in WPF only. This is how it would look:

  1. public int Columns {
  2.     get { return (int)GetValue(ColumnsProperty); }
  3.     set { SetValue(ColumnsProperty, value); }
  4. }
  5.  
  6. public int Rows {
  7.     get { return (int)GetValue(RowsProperty); }
  8.     set { SetValue(RowsProperty, value); }
  9. }
  10.  
  11. public static readonly DependencyProperty ColumnsProperty =
  12.      DependencyProperty.Register("Columns", typeof(int), typeof(UniformGrid), new PropertyMetadata(1, OnColumnsChanged));
  13.  
  14.  
  15. public static readonly DependencyProperty RowsProperty =
  16.      DependencyProperty.Register("Rows", typeof(int), typeof(UniformGrid), new PropertyMetadata(1, OnRowsChanged));

The OnColumnsChanged and OnRowsChanged are just there to make sure the properties have the value greater than zero:

  1. static void OnColumnsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) {
  2.     int cols = (int)e.NewValue;
  3.     if(cols < 1)
  4.         ((UniformGrid)obj).Columns = 1;
  5. }
  6.  
  7. static void OnRowsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) {
  8.     int rows = (int)e.NewValue;
  9.     if(rows < 1)
  10.         ((UniformGrid)obj).Rows = 1;
  11. }

 

MeasureOverride

This method accepts the available space from the panel’s parent. It’s actually possible to get double.PositiveInfinity for the Width and/or Height of the received size. This would mean the panel can have as much space as it wants (a classic example of this is if the panel is hosted in a ScrollViewer, which usually gives infinite space to its child – I say usually, because it depends on the Horizontal/VerticalScrollBarVisibility properties… but that’s a topic for another post).

The method must call the Measure method on each child. This is required, because the child may depend on it. In our case, we don’t really care, because every child is going to get equal space – still, we must call Measure.

We have to return the size we’re actually going to use, and it must not be double.PositiveInfinity in the Width or Height. Here’s a simple implementation:

  1. protected override Size MeasureOverride(Size availableSize) {
  2.     foreach(UIElement child in Children)
  3.         child.Measure(availableSize);
  4.  
  5.     return new Size(double.IsPositiveInfinity(availableSize.Width) ? 0 : availableSize.Width,
  6.         double.IsPositiveInfinity(availableSize.Height) ? 0 : availableSize.Height);
  7. }

We probably don’t need much more than that for the UniformGrid. Note that WPF’s UniformGrid has another property, FirstColumn, that we won’t implement.

ArrangeOverride

In this phase, the panel tells the children what they get. Here’s a possible implementation:

  1. protected override Size ArrangeOverride(Size finalSize) {
  2.     Size cellSize = new Size(finalSize.Width / Columns, finalSize.Height / Rows);
  3.     int row = 0, col = 0;
  4.     foreach(UIElement child in Children) {
  5.         child.Arrange(new Rect(new Point(cellSize.Width * col, cellSize.Height * row), cellSize));
  6.         if(++col == Columns) {
  7.             row++;
  8.             col = 0;
  9.         }
  10.     }
  11.     return finalSize;
  12. }

We calculate the size of each “cell” and tell each child its exact position and size by calling the UIElement.Arrange method, passing in a Rect structure.

And we’re basically done. Note that the implementation is not foolproof: if an element has a Collapsed Visibility, we still give it space. We should really skip it. I’ll leave that as an exercise to the motivated reader.

Testing

Let’s use this in a Silverlight Windows Phone application that would show the user’s pictures library in an ItemsControl that uses our UniformGrid. (I know, we can use a WrapPanel from the Windows Phone toolkit to get a similar effect if we’re careful).

Here’s the basic XAML:

  1. <ItemsControl x:Name="_pics">
  2.     <ItemsControl.ItemsPanel>
  3.         <ItemsPanelTemplate>
  4.             <local:UniformGrid Rows="5" Columns="4" />
  5.         </ItemsPanelTemplate>
  6.     </ItemsControl.ItemsPanel>
  7.     <ItemsControl.ItemTemplate>
  8.         <DataTemplate>
  9.             <Grid Margin="4">
  10.                 <Image Source="{Binding Image}" />
  11.                 <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center"
  12.                            Text="{Binding Name}" FontSize="16" />
  13.             </Grid>
  14.         </DataTemplate>
  15.     </ItemsControl.ItemTemplate>
  16. </ItemsControl>

I’m assuming we’ll bind to a collection that has a Name and Image properties. The ItemsPanel property is using our UniformGrid. “local” is the XML namespace prefix I selected.

All that’s left now is get the pictures and bind. We’ll do that in the MainPage constructor:

  1. public partial class MainPage : PhoneApplicationPage {
  2.     public class PictureInfo {
  3.         public string Name { get; set; }
  4.         public ImageSource Image { get; set; }
  5.     }
  6.  
  7.     public MainPage() {
  8.         InitializeComponent();
  9.  
  10.         var library = new MediaLibrary();
  11.         var pictures = library.Pictures;
  12.         var display = from p in pictures
  13.                           select new PictureInfo {
  14.                               Name = p.Name,
  15.                               Image = GetImage(p)
  16.                           };
  17.         _pics.ItemsSource = display;
  18.     }
  19.  
  20.     private ImageSource GetImage(Picture p) {
  21.         var bmp = new BitmapImage();
  22.         bmp.SetSource(p.GetThumbnail());
  23.         return bmp;
  24.     }
  25. }

This is the entire MainPage code behind. We use the MediaLibrary class (from Microsoft.Xna.Framework) to get the pictures using the Pictures property. We can’t bind directly to this collection, because the images are not supplied as properties of type ImageSource; in fact, they’re methods. So, we need a little bit of LINQ projection to transform this collection to a new one with properties, suitable for binding. That’s where the GetImage method comes in. It calls Picture.GetThumbnail() and builds a BitmapImage to hold the result (an ImageSource derivative).

The PictureInfo class is our little helper to hold the data. If you wander why an anonymous type wasn’t used, that’s because Silverlight doesn’t like using internal types (which anonymous types always are) when data binding. So, I had to create a new public type.

Running this in the emulator results in something like this (thanks to some default pictures the emulator comes with):

image

A New Android Game in Town (by my brother)

Published at Feb 05 2012, 10:36 PM by pavely

Anyone who has ever written a game knows it’s hard to get it done from start to finish. Sure, I can put on a demo of some game I’ve created in several hours. But creating all the graphics, sound, animation, levels, transitions, scoring, etc, from start to finish is quite a challenge, especially for a single developer.

That’s why I’m very proud of my young brother, Yaniv, that has worked hard for the past 10 months (while maintaining a proper day job!) on an awesome  fun game called Micro Wars, targeted for the Android platform. This game plays especially well on tablets, with their bigger screen and powerful processors.

Here’s the trailer on you tube:

 

The demo version (free) can be downloaded from here: https://market.android.com/details?id=com.psychocat.microwars.demo

The paid version is here: https://market.android.com/details?id=com.psychocat.microwars

There’s also a facebook page: http://www.facebook.com/pages/Micro-Wars-HD/326100820757989

Great job, Yaniv!

Next Windows Devices User Group Meeting

Published at Feb 05 2012, 10:19 PM by pavely

The second meeting of the Windows Devices User Group will be held on February 28th, at 17:00, Microsoft Offices in Ra’anana. The registration link and detailed agenda is here: http://windowsphonenavandlifecycle.eventbrite.com/

In this meeting we’ll talk about page navigation and the application lifecycle, which got a bit more complicated (but performs better) in the “Mango” release. We’ll also hear a “real life story” of porting an application to Windows Phone.

See you there!