Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Designing FreeCell using Expression and Visual Studio Toolsets

  This article re-creates the game FreeCell using the January CTP and Visual Studio 2005 Express.
Unni's Blog

Difficulty: Intermediate
Time Required: 3-6 hours
Software: Visual Studio Express Editions, Microsoft Expression Interactive Designer, Windows Vista, .NET Framework 3.0 Runtime and Windows SDK Downloads
Download:

Microsoft is starting to make some of the new development technology for Windows Vista available to programmers through Community Technology Preview (CTP) releases. To start introducing this technology to you (and have a little fun with it myself), I decided to recreate the game FreeCell using the January CTP and Visual Studio 2005 Express. In this article, I will try and describe my experiences on this brief one-day journey and how much fun it turned out to be!

About the technology used

"Windows Presentation Foundation", "Windows Communication Foundation", and "Windows Workflow Foundation" are the names for three strategic developer technologies that Microsoft plans to ship in 2006 as part of the Windows Vista operating system. In addition, Microsoft is making these technologies available on Windows XP and Windows Server 2003. The WinFX Runtime Components January CTP enables developers to continue experimenting with early builds of these technologies, get acquainted with the development experience, and provide Microsoft with feedback.

"Windows Presentation Foundation" is the name for Microsoft's unified presentation subsystem for Windows, formerly known as "Avalon". It consists of a display engine and a managed-code framework. "Windows Presentation Foundation" unifies how Windows creates, displays, and manipulates documents, media, and user interface. This enables developers and designers to create visually-stunning, differentiated user experiences that improve customer connection. When delivered, "Windows Presentation Foundation" will become Microsoft's strategic user interface (UI) technology.

Microsoft Expression Interactive Designer allows you to create engaging, cinematic user interfaces with a rich design environment that combines multiple media elements including vectors, pixel images, 3D content, video and audio, high-quality text, and animation. It allows you to drive seamless collaboration with developers using Visual Studio and maximize the integrity of designs by sharing the common WinFX platform during prototype, design, and development stages of building advanced UI and applications. For more information, visit http://www.microsoft.com/expression.

Creating the Game

When I set out on this project, I only had one goal in mind: I wanted to understand the workflow in designing an application in collaboration with a developer.

The first thing I did was to create all the card visuals once I knew I was doing FreeCell. All of the visuals are vectors done in Interactive Designer. Essentially, there are four drawing brushes for the four suites (created using the Tools | Make Tile Brush | Make Drawing Brush option in Interactive Designer).

FreeCell uses the Model View Controller (MVC) pattern that WPF makes very easy to implement using its powerful data-binding feature. The model for the card game resides in 4 classes:

  • Card.cs defines Card, which is your regular card data structure.
  • Cell.cs defines Cell. FreeCell has two kinds of cells: Home and Free.
  • GameModel.cs defines GameModel, which is the main game engine and holds the data structures for the various card stacks and cells.
  • RandomCardGenerator.cs defines a helper class that helps generate cards in random order using Enumeration – I brought this type in from a previous card game I wrote.

GameModel exposes all the data-structures as properties, such as HomeCells (which is a collection of home cells), FreeCells and CardStacks. CardStacks is a collection of collections, each of which is collection of Cards. Using ObservableCollection (which is derived from IList) allows you to simply tweak the model (such as moving a card from one stack to another whenever a game event happens) and this will update the UI. All of this requires no UI manipulation code. GameModel also exposes a string for displaying the time on the game board. For ensuring that the UI updates each time a timer in the model ticks, you need to implement an Interface called INotifyPropertyChanged, which will fire a PropertyChanged event whenever a property changes. You can then bind against this property in the view and forget about it. Isn't that a sweet separation between model and view?

So much for the code. An Expression project flows smoothly into Visual Studio and back since they share the same infrastructure underneath – any changes you make in Expression are visible in Visual Studio and vice versa!

The next step was to get back into Expression Interactive Designer and make this thing look cool. I used a ViewBox at the root of the game board (minus the status-bar-like thing) so that things would scale correctly when the app was resized—one of the biggest complaints I have with the FreeCell that ships with Windows. Expression has powerful layout capabilities that make it every easy to control behavior when the app is resized, and you can do this without it being your main concern.

A custom Panel was required for stacking the various cards, so I put my developer hat back on and created CardStackPanel.cs. It exposes an Offset property that allows the designer to control the Offset on the design surface. The code for this type is shown below and shows how easy it is to extend functionality of pre-existing controls in WPF:

Visual C#

public class CardStackPanel : StackPanel
{
public double ArrangeOffset
{
get { return (double)base.GetValue(ArrangeOffsetProperty); }
set { base.SetValue(ArrangeOffsetProperty, value); }
}

public static readonly DependencyProperty ArrangeOffsetProperty =
DependencyProperty.Register("ArrangeOffset",
typeof(double), typeof(CardStackPanel), new PropertyMetadata(10.0));

protected override Size ArrangeOverride(Size arrangeSize)
{
Rect childArrangeRect = new Rect(arrangeSize);
childArrangeRect.Y = -1 * this.ArrangeOffset;

for (int i = 0; i < this.InternalChildren.Count; i++)
{
UIElement child = this.InternalChildren[i];
childArrangeRect.Y += this.ArrangeOffset;
childArrangeRect.Height = child.DesiredSize.Height;
child.Arrange(childArrangeRect);
}

return arrangeSize;
}
}

Visual Basic

Public Class CardStackPanel Inherits StackPanel
Public Property ArrangeOffset() As Double
Get
Return CDbl(MyBase.GetValue(CardStackPanel.ArrangeOffsetProperty))
End Get
Set(ByVal value As Double)
MyBase.SetValue(CardStackPanel.ArrangeOffsetProperty, value)
End Set
End Property

Public Shared ReadOnly ArrangeOffsetProperty As DependencyProperty

Shared Sub New()
CardStackPanel.ArrangeOffsetProperty = _
DependencyProperty.Register("ArrangeOffset", GetType(Double), _
GetType(CardStackPanel), New PropertyMetadata(10.0))
End Sub

Protected Overrides Function ArrangeOverride(ByVal arrangeSize As Size) _
As Size
Dim childArrangeRect As New Rect(arrangeSize)
childArrangeRect.Y = (-1 * Me.ArrangeOffset)
Dim childIdx As Integer = 0
Do While (childIdx < MyBase.InternalChildren.Count)
Dim child As UIElement = MyBase.InternalChildren.Item(childIdx)
childArrangeRect.Y = (childArrangeRect.Y + Me.ArrangeOffset)
childArrangeRect.Height = child.DesiredSize.Height
child.Arrange(childArrangeRect)
childIdx += 1
Loop
Return arrangeSize
End Function

The rest of the UI creation was a breeze using Expression's powerful data-binding feature: just drag and drop data (like the time string that you created previously in your model), choose the control that you want to display the data (in this case a TextBlock), select the property you want to bind to (Text in our case), and finally, for more complex data fields, customize the look. To create a stack of stacks for the various cards on the game board, I used the default StackPanel that WPF provides (in horizontal mode) and each collection within it was laid out using the custom panel I wrote (and I set the Offset property to a value that made this look good).

One of the tricky things is that there really are no cards in these various data structures until the game actually beings; so, to workaround that, I wrote some temporary code in the constructor of my GameModel to populate them—that way I could visualize the cards and design them. We are working on providing a better solution to this problem so that you really won't have to write this kind of temporary code in the future.

There are two more interesting things: the design for the cards and the interactivity. At this point, you have four drawing brushes. How do you convert this to form fifty-two cards? The solution is to use the very powerful DataTrigger feature that WPF exposes. Data triggers allow you to specify the look of the visual based on a property in the model (in this case the Suite and Card number information). So I created thirteen data triggers for the thirteen possible cards, and four additional data triggers for the four suites. Each card template uses the Brush set on the control that represents it and thus you have 13 * 4 cards—cool, eh? Unfortunately, you cannot create DataTriggers in Interactive Designer as of now, so it has to be done by editing the markup. However, once this is done, you can then leverage the power of Interactive Designer to figure out what your Queen of Hearts or Ace of Spades should look like.

Here is what the structure of the DataTemplate for a Card looks like:

<DataTemplate x:Key="CardTemplate">
<Grid x:Name="Grid1" Width="72" Height="100">
<ColumnDefinition/>
<RowDefinition/>
<Control x:Name="CardDisplayControl" Margin="2,0,2,0"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Width="Auto" Height="Auto" />
....
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Suite}">
<DataTrigger.Value>
<FreeCell:Suite>Hearts</FreeCell:Suite>
</DataTrigger.Value>
<Setter Property="Foreground" TargetName="CardDisplayControl"
Value="{StaticResource HeartsDrawingBrush}" />
</DataTrigger>
....
<DataTrigger Binding="{Binding SuiteIndependentCardNumber}">
<DataTrigger.Value>
<system:Int32>1</system:Int32>
</DataTrigger.Value>
<Setter Property="Template" TargetName="CardDisplayControl"
Value="{StaticResource AceTemplate}"/>
</DataTrigger>
....
</DataTemplate.Triggers>
</DataTemplate>

 There are two kinds of interactivity possible in this game: starting the game and selecting cards. To start the game, I used yet another WPF feature called command binding. Command binding allows your command implementation to be in your model (which in this case involves resetting the data structures, timers, etc.) without have to worry about how the command will be exposed. To hook up the command, you again use—guess what—data-binding using drag-drop in Interactive Designer: you can hook up the command to a button, menu item or both if you like. If the command is not available, then these various UI elements appear disabled—all without a line of UI code.

Finally to figure out which card or cell was hit by the user, all one has to do is to add a MouseDown event. Look at the DataContext property on the sender of the event. If the DataContext is not null and is an object in your model, you know exactly what was hit (at this point, all you do is call a function into your model to execute the game logic).

Check it out! It sure is fun!

Tags:

Follow the Discussion

  • OneHorseTownManOneHorseTown​Man

    I can't get the sample code to build under Vista RC1, or with the September CTP of .net v3 and Windows SDK.

    I've tried updating the xmlns declarations which remove a large number of the errors generated by the compiler but the declaration for 'ignorable' for the markup-compatibility schema still causes a problem.

    Is there any chance of seeing amended code for this programming example?

  • LouisLouis

    Ditto here... I get the following compile error:

    MainWindow.xaml(17,5): error MC3074: The tag 'GameModel' does not exist in XML namespace 'FreeCell'. Line 17 Position 5.

    When removing the offending line I get further errors also having to do with tags not existing even for simple things such as the System:Int32 definition.

    I am using DevStudio Team Ed. for Developers 2005 with Cider extensions and Blend RC1 is installed but I'm not using that to build.

  • Moshe PlotkinMoshe Plotkin

    did you have any luck with finding an ameded code for this article?

  • KarlKarl

    I got the project to run.  Took awhile to sort it all out.  If you go to my blog : http://karlshifflett.wordpress.com/

    and leave a comment and your email, I'll send you a working version.  I use VS 2005 and Blend.

    Karl

  • kolaikolai

    May you convert this code to C++ language??

    Need this so badly.

    thanks.

  • ge-forcege-force

    COuld you recommend a good tutorial on msdn or coding4fun on how to create a windows forms card game?

  • Clint RutkasClint I'm a "developer"

    @ge-force I'm betting CodeProject has a ton of card games.

  • Clint RutkasClint I'm a "developer"

    @ninja4 www.CodeProject.com

  • ninja4ninja4

    Could you please send me a link to CodeProject?

    Thanks,

    ninja

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.