Windows Phone Application Bar Icons: Gotcha

I wanted to toggle my Panzer General game between air and ground mode. To do so, I created an Icon Button like so:

1 <shell:ApplicationBarIconButton x:Name="airSurface" Text="air/surface" IconUri="Images/appbar.upload.rest.png" Click="airSurface_Click" />

I then wired up the code-behind like so:

1 if (Game.InGroundMode) 2 { 3 this.airSurface.IconUri = new Uri(@"/Images/appbar.upload.rest.png", UriKind.Relative); 4 Game.InGroundMode = false; 5 } 6 else 7 { 8 this.airSurface.IconUri = new Uri(@"/Images/appbar.download.rest.png", UriKind.Relative); 9 Game.InGroundMode = true; 10 } 11

When I ran it, I got this:

image

I first thought – I must have the url wrong. I double checked the properties of the icon images – they are content. After screwing around with url and paths for a bit, it dawned on me that perhaps the uri was fine. Sure enough, when I separated the uri creation into its own line, the error was on the IconUri assignment – the button is null! For someone used to WinForms/WebForm programming, this was unexpected.

image

Jumping back to Nathan’s excellent book, I see that he has a different way of referring to IconButtons in code. I updated my code to this:

1 IApplicationBarIconButton button = sender as IApplicationBarIconButton; 2 3 if (Game.InGroundMode) 4 { 5 Uri uri = new Uri(@"/Images/appbar.upload.rest.png", UriKind.Relative); 6 button.IconUri = uri; 7 Game.InGroundMode = false; 8 } 9 else 10 { 11 button.IconUri = new Uri(@"/Images/appbar.download.rest.png", UriKind.Relative); 12 Game.InGroundMode = true; 13 } 14

And it now toggles as expected

So the two lessons are:

1) When 1 line of code does the work on two, you are setting yourself up for debugging headaches. Separate 1st, then consolidate

2) Just b/c it looks like a duck, walks like a duck, and quacks like a duck; it doesn’t mean that it follows the other APIs that you are used to….

A curious property about dependency properties

For my Panzer General game, I have a collection of hexes that make up the main board. Before every turn, I update the main canvas with this collection. I wrote some code like this:

this.MainCanvas.Children.Clear(); foreach (Hex hex in Game.CurrentBoard) { hex.HexInfoTextBlock.Text = string.Empty; this.MainCanvas.Children.Add(hex); }

However, when I run it, I get the following exception:

 

System.InvalidOperationException was unhandled

Message=Element is already the child of another element.

 

My first thought was to create a Clone for each Hex – remove the old Hex and then add the new one to the collection. However, I still got the same error.

After mucking around Bing for a bit (and not getting any closer to the answer), I decided to back into the parent and try and clear the collection that way:

Canvas currentCanvas = Game.CurrentBoard[0].Parent as Canvas; if (currentCanvas != null) { currentCanvas.Children.Clear(); }

Surprise! Surprise! It worked. I am guessing that the dependency property of the children still hold onto their parent even after the clear until the page goes out of scope.

Using LINQ to replace foreach

I sometimes forget how powerful LINQ can be – especially when dealing with older constructs that work fine.  I recently wrote this nugget of crappy code:

Unit unit = null; foreach (Hex hex in Game.CurrentBoard) { if (hex.CurrentUnit != null) { if (hex.CurrentUnit.Country.AlliesIndicator == true) { unit = hex.CurrentUnit; } } }

I looked at it for a second and then re-wrote it using LINQ:

var q = (from h in Game.CurrentBoard where h.CurrentUnit.Country.AlliesIndicator == true select h);

Take about an improvement in readability!

Removing something from a collection

Consider the following snippet:

//Remove all hexes that have a unit in them for (int i = 0; i < returnValue.Count; i++ ) { if (returnValue[i].CurrentUnit != null) { returnValue.RemoveAt(i); } } return returnValue;

This does not work.  For example, here is a screen shot:

image

The reason why is that the indexer is evaluated once,, but the list changes after each iteration.  In graphical terms:

0

1

2

3

4

5

X

X

0

1

2

3

4

X

 

 

Index 1 becomes Index 0, and since the loop is already on 1, it gets skipped for evaluation. What we need it to remove a hex and then keep looping – so the while construct needs to be used:

bool keepLooping = true; while (keepLooping == true) { int totalHexes = returnValue.Count; for (int i = 0; i < returnValue.Count; i++) { if (returnValue[i].CurrentUnit != null) returnValue.RemoveAt(i); if (totalHexes == returnValue.Count) keepLooping = false; } }

 

And the results work as expected:

image

Windows Phone 7 Game: Getting Closer

I have spent the last month or so writing a port of Panzer General to a Windows Phone 7 application. 

Here is a screen shot of the original game:

image

Here is a screen shot from my phone app:

image

And here it is after pinching:

image

There is 1 thing I don’t like about the graphics – each hex has a copy of the underlying image.  I really only need 1 in memory so I will make that change – which should improve the game load time.