<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Coding4Fun : card and board games</title><link>http://blogs.msdn.com/coding4fun/archive/tags/card+and+board+games/default.aspx</link><description>Tags: card and board games</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Building Multiplayer Texas Holdem Poker For The Zune</title><link>http://blogs.msdn.com/coding4fun/archive/2009/05/05/9582637.aspx</link><pubDate>Tue, 05 May 2009 22:06:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9582637</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/9582637.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=9582637</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=9582637</wfw:comment><description>&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/BuildingMultiplayerTexasHoldemPokerForTh_10423/clip_image002_2.gif"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="clip_image002" border="0" alt="clip_image002" align="right" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/BuildingMultiplayerTexasHoldemPokerForTh_10423/clip_image002_thumb.gif" width="240" height="320" /&gt;&lt;/a&gt;Have you ever been interested in creating a game that harnesses XNA’s powerful network library to create multiplayer experiences for the Zune device?&lt;/p&gt;  &lt;p&gt;The Zune firmware version 3.1 brought us a professionally built incarnation of Texas Holdem that supports network play. Understanding how to send and receive data with the Zune can be a little daunting at first, but once you understand the pattern, it’s easy. &lt;/p&gt;  &lt;p&gt;To build out the entire game, you probably need about a week, but you can build some simpler examples in far less time. &lt;/p&gt;  &lt;p&gt;This is an earlier project from before the release of my &lt;a href="http://www.tinyurl.com/zunebook"&gt;Zune game development book&lt;/a&gt;. Accordingly, some of the code samples you see in this article may be inconsistent with what you find in the download. The code in the article is the “correct” way to do things. The code in the download is still a work in progress.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;b&gt;Source Code:&lt;/b&gt; &lt;a href="https://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=zuneholdem&amp;amp;ReleaseId=2382"&gt;Download&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Difficulty &lt;/b&gt;Intermediate|Advanced &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Time Required:&lt;/b&gt; 40 hours &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Hardware:&lt;/b&gt; 2x &lt;a href="http://www.amazon.com/Zune-Video-MP3-Player-Black/dp/B001EWDFCI/ref=pd_bbs_sr_3?ie=UTF8&amp;amp;s=electronics&amp;amp;qid=1237183912&amp;amp;sr=8-3"&gt;Zune&lt;/a&gt; devices ($170 ea) &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Software Needed:&lt;/b&gt; &lt;a href="http://www.microsoft.com/express/download/"&gt;Visual C# Express&lt;/a&gt;, &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=7d70d6ed-1edd-4852-9883-9a33c0ad8fee&amp;amp;displaylang=en"&gt;XNA Game Studio 3.0&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;The Workflow&lt;/h3&gt;  &lt;p&gt;Developing multiplayer games for the Zune is interesting because you have to deploy to each device individually. Once you have a build that works for you, it’s helpful to run-deploy (Control+F5) to one device, leave it running there, and then plug in the other Zune and debug-deploy (F5) to it. This way you have one debuggable instance of the game running. Make sure to set the appropriate Zune device as the default in the XNA Game Studio Device Center (accessible from the Tools menu).&lt;/p&gt;  &lt;h3&gt;Starting A Network Session&lt;/h3&gt;  &lt;p&gt;Because the Zunes connect over an ad-hoc, peer-to-peer connection rather than through an access point, you will have to designate one Zune as the host device. The host is usually determined to be the one that creates a new game. Therefore, all Zunes that join the host’s network session are simply peers. The difference between the host and the peers is that the host usually maintains the game state on top of executing the game as well, because the game data has to be centralized somewhere. Keep that in mind, because if one Zune is doing substantially more processing, it can lag behind and mess up your network session. Also, remember that all Zunes are running the exact same copy of the game, so the game must support both host and peer scenarios.&lt;/p&gt;  &lt;h4&gt;Create / Join / Lobby Model&lt;/h4&gt;  &lt;p&gt;Most peer-to-peer connected games allow a user to create or join a game. After doing so, the player is funneled into an area called the Lobby where they can specify their readiness. When all players are ready, the host can start the game. Some of this functionality is provided directly by the XNA Framework’s Net and GamerServices libraries. &lt;/p&gt;  &lt;p&gt;I normally create three separate screens based on the &lt;a href="http://creators.xna.com/en-US/sample/network_game_state_mgt_sample"&gt;Network Game State Management sample&lt;/a&gt; from the Creators Club website. The first is the Create screen, which looks exactly like a lobby. It starts up a network session and waits for players to join and become ready. The code to create a network session looks like this (note that I have employed some abstraction to make my code a little more cohesive):&lt;/p&gt;  &lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateZuneSession(&lt;span class="kwrd"&gt;int&lt;/span&gt; maxNetworkPlayers)
{
    KillSession();

    &lt;span class="kwrd"&gt;try&lt;/span&gt;
    {
        Session = NetworkSession.Create(NetworkSessionType.SystemLink, 1,      
            maxNetworkPlayers); 
        Me = Session.LocalGamers[0];
    }
    &lt;span class="kwrd"&gt;catch&lt;/span&gt; (NetworkNotAvailableException)
    {
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; NetworkNotAvailableException(&lt;span class="str"&gt;&amp;quot;Zune wireless is not 
            enabled.&amp;quot;&lt;/span&gt;);
    }
    &lt;span class="kwrd"&gt;catch&lt;/span&gt; (NetworkException ne)
    {
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; ne;
    }

    &lt;span class="kwrd"&gt;if&lt;/span&gt; (Session == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; NetworkException(&lt;span class="str"&gt;&amp;quot;The network session could not be 
            created.&amp;quot;&lt;/span&gt;);
}&lt;/pre&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;All Zune network sessions are of the type SystemLink, much like LAN-networked Xbox consoles. The ‘1’ parameter specifies the number of local players – of course, on a Zune, there can only be one.&lt;/p&gt;

&lt;p&gt;This line of code sets the Session property to a newly created network session. The Join screen, running on another Zune, will find this session asynchronously as an available network session and attempt to join it. The first step is to enumerate available network sessions:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C# 
    &lt;br /&gt;&lt;/b&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span class="rem"&gt;/// Asynchronous: Begins to discover network sessions.&lt;/span&gt;
&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; BeginGetAvailableSessions()
{
    &lt;span class="rem"&gt;// Destroy any existing connections&lt;/span&gt;
    KillSession();

    NetworkSession.BeginFind(NetworkSessionType.SystemLink, 1, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; 
        AsyncCallback(SessionsFoundCallback), &lt;span class="kwrd"&gt;null&lt;/span&gt;);
}&lt;/pre&gt;

&lt;p&gt;This code looks for SystemLink sessions and calls the callback method SessionsFoundCallback when the operation completes (successfully or unsuccessfully). If sessions are found, an event is fired. Other screens can subscribe to this event and transition to other screens or do other processing with the network session.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span class="rem"&gt;/// Called when network sessions are found.&lt;/span&gt;
&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;result&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SessionsFoundCallback(IAsyncResult result)
{
    AvailableNetworkSessionCollection availableSessions = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
    availableSessions = NetworkSession.EndFind(result);

    &lt;span class="kwrd"&gt;if&lt;/span&gt; (NetworkSessionsFound != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
        NetworkSessionsFound(availableSessions);
}        &lt;/pre&gt;

&lt;p&gt;When all players are ready and the host presses the middle button, the network session’s StartGame() method is called, which will cause all connected peers to receive a GameStarted event. This loads up the playing screen.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (allPlayersReady &amp;amp;&amp;amp; atLeastTwoPlayers)
{
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (ScreenManager.Network.Session != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
        ScreenManager.Network.Session.StartGame();
}&lt;/pre&gt;

&lt;p&gt;That’s basically how to connect up two Zunes in a network session. See my &lt;a href="http://www.tinyurl.com/zunebook"&gt;book&lt;/a&gt; for a much more detailed explanation.&lt;/p&gt;

&lt;h3&gt;Dealing With Cards&lt;/h3&gt;

&lt;p&gt;As Poker is a card game, you might want to develop a testable, standalone library that you can use not only to house your objects, but also to write out all the intense logic required for a game like poker. The task of determining what a player’s best hand is out of seven cards (and whether it beats another player’s hand) is more in-depth than you might expect. &lt;/p&gt;

&lt;p&gt;An easy way to go about this is to create a Zune game library. I called mine CardLib. CardLib has objects such as these:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Card which has a suit, a value, some comparers and some utility methods) &lt;/li&gt;

  &lt;li&gt;Deck, which has a collection of cards and methods like Shuffle, ResetDeck, etc. &lt;/li&gt;

  &lt;li&gt;Dealer, which has a deck, a list of the five community cards, and methods like Shuffle, DealCard, Burn, DealFlop, DealTurn, etc. &lt;/li&gt;

  &lt;li&gt;HoldemHand, which contains all of the logic for determining what a hand is (always 7 cards) &lt;/li&gt;

  &lt;li&gt;BestHand, which takes a HoldemHand and determines what the best possible hand is within that hand &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Shuffling Cards&lt;/h4&gt;

&lt;p&gt;Shuffling cards is surprisingly easy. I use the &lt;a href="http://www.codinghorror.com/blog/archives/001015.html"&gt;Knuth-Fisher-Yates shuffling algorithm&lt;/a&gt;, which takes every card in the deck and randomly swaps it with another.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C# 
    &lt;br /&gt;&lt;/b&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span class="rem"&gt;/// Knuth-Fisher-Yates shuffling algorithm:&lt;/span&gt;
&lt;span class="rem"&gt;/// http://www.codinghorror.com/blog/archives/001015.html&lt;/span&gt;
&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Shuffle()
{
    Random rand = &lt;span class="kwrd"&gt;new&lt;/span&gt; Random();
    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; cardIndex = _cards.Count - 1; cardIndex &amp;gt; 0; cardIndex--)
    {
        &lt;span class="kwrd"&gt;int&lt;/span&gt; randomIndex = rand.Next(cardIndex + 1);
        SwapCardsByIndex(cardIndex, randomIndex);
    }
    _dealIndex = 0;
}&lt;/pre&gt;

&lt;h4&gt;Poker Logic&lt;/h4&gt;

&lt;p&gt;An example method you’ll see in this library is this snippet to check if the hand is a royal flush:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C# 
    &lt;br /&gt;&lt;/b&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsRoyalFlush(&lt;span class="kwrd"&gt;out&lt;/span&gt; List&amp;lt;Card&amp;gt; winningCards)
{
    List&amp;lt;Card&amp;gt; straightFlushCards;

    &lt;span class="kwrd"&gt;if&lt;/span&gt; (IsStraightFlush(&lt;span class="kwrd"&gt;out&lt;/span&gt; straightFlushCards))
    {                
        &lt;span class="rem"&gt;// Check to make sure the straight flush cards are: 10 J Q K A&lt;/span&gt;
        straightFlushCards.Sort();

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (straightFlushCards[0].Value == 10 &amp;amp;&amp;amp;
            straightFlushCards[1].Value == Card.Jack &amp;amp;&amp;amp;
            straightFlushCards[2].Value == Card.Queen &amp;amp;&amp;amp;
            straightFlushCards[3].Value == Card.King &amp;amp;&amp;amp;
            straightFlushCards[4].Value == Card.Ace)
        {
            winningCards = straightFlushCards;
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        }

        &lt;span class="kwrd"&gt;else&lt;/span&gt;
        {
            winningCards = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;
        }
    }
    &lt;span class="kwrd"&gt;else&lt;/span&gt;
    {
        winningCards = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;
    }
}&lt;/pre&gt;

&lt;p&gt;There is a ton of similar and even more disgusting logic to peruse in the HoldemHand.cs file in the region entitled “Poker Logic Fun Times.” This logic covers every possible poker hand and could probably be refactored to be way more elegant.&lt;/p&gt;

&lt;p&gt;When it comes time to evaluate the winner, each player’s best hand is determined and they are evaluated against each other to determine the winner. This code returns a list of WinnerInfo objects, which returns the player info and a list of the cards they won with.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;WinnerInfo&amp;gt; DetermineWinners()
{
    BestHand overallBestHand = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
    HoldemPlayer winner = &lt;span class="kwrd"&gt;null&lt;/span&gt;;

    List&amp;lt;WinnerInfo&amp;gt; winners = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;WinnerInfo&amp;gt;();

    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (HoldemPlayer player &lt;span class="kwrd"&gt;in&lt;/span&gt; _players)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (player.Status != PlayerStatus.Folded)
        {
            HoldemHand tempHand = &lt;span class="kwrd"&gt;new&lt;/span&gt; HoldemHand(player.Pocket, _communityCards);
            BestHand bestHand = tempHand.GetBestHand();

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (overallBestHand == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="rem"&gt;// if there is no best hand yet&lt;/span&gt;
            {
                overallBestHand = bestHand;
                winner = player;
                winners.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; WinnerInfo(overallBestHand, winner, Me));
            }
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
            {
                &lt;span class="rem"&gt;// if this hand beats the current best hand&lt;/span&gt;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (BestHand.Beats(bestHand, overallBestHand))
                {
                    winners.Clear();
                    overallBestHand = bestHand;
                    winner = player;
                    winners.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; WinnerInfo(overallBestHand, winner, Me));
                }
                &lt;span class="kwrd"&gt;else&lt;/span&gt;
                {
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (BestHand.IsEquivalentTo(bestHand, overallBestHand))
                    {
                        winners.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; WinnerInfo(bestHand, player, Me));
                    }
                }
            }
        }
    }

    _winners = winners;
    &lt;span class="kwrd"&gt;return&lt;/span&gt; winners;
}&lt;/pre&gt;

&lt;h4&gt;Drawing Cards On The Screen&lt;/h4&gt;

&lt;p&gt;Rather than have 52 different sprites that represent each possible card, I just made my own sheet of Zune-sized playing cards. Horizontally, they are ordered by value (1-13) and vertically they are ordered by suit (both alphabetically and corresponding to the numeric value of the Suit enumeration in the project, 1-4).&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/BuildingMultiplayerTexasHoldemPokerForTh_10423/clip_image004_2.gif"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image004" border="0" alt="clip_image004" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/BuildingMultiplayerTexasHoldemPokerForTh_10423/clip_image004_thumb.gif" width="572" height="240" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a specific card is requested to be drawn, a formula is used to calculate the source rectangle from this larger image. This is very similar to how fonts worked before spritefonts were introduced into XNA. This allows us to strip out the graphic of a specific card and draw it onscreen at some other location.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C# 
    &lt;br /&gt;&lt;/b&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; DrawCard(Card card, Vector2 position)
{
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (card != Card.Undefined &amp;amp;&amp;amp; card.Suit != Suit.Unassigned)
        ScreenManager.SpriteBatch.Draw(_texDeck, position, GetCardSourceRect(card), Color.White);
}

&lt;span class="kwrd"&gt;private&lt;/span&gt; Rectangle GetCardSourceRect(Card card)
{
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (card.Suit == Suit.Unassigned)
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentException(&lt;span class="str"&gt;&amp;quot;Unassigned cards cannot be drawn.&amp;quot;&lt;/span&gt;);

    &lt;span class="kwrd"&gt;int&lt;/span&gt; cardColumn = card.Value - 1;
    &lt;span class="kwrd"&gt;int&lt;/span&gt; cardRow = (&lt;span class="kwrd"&gt;int&lt;/span&gt;)card.Suit - 1;

    &lt;span class="kwrd"&gt;int&lt;/span&gt; x = cardColumn * MainScreenElements.CARD_WIDTH;
    &lt;span class="kwrd"&gt;int&lt;/span&gt; y = cardRow * MainScreenElements.CARD_HEIGHT;

    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Rectangle(x, y, MainScreenElements.CARD_WIDTH, MainScreenElements.CARD_HEIGHT);
}&lt;/pre&gt;

&lt;h3&gt;Managing Network Data&lt;/h3&gt;

&lt;p&gt;One thing that increases the complexity of this game (in no small way) is the management of network data. First of all, the host’s actions are a superset of the peer’s actions (a host is also a peer, but it also has to manage the game and network state). For example, when a peer decides to bet, it has to send a message to the host saying “I would like to bet,” and then the host will process that message and relay it to the other peers. The host is also responsible for managing whose turn it is and determining who the winner is. Theoretically, you could do a lot of this with every peer acting equally but it feels safer to me to have the host responsible for important activities like dealing cards. In fact, the host has to be the only one who can deal cards, because if each client maintained its own deck, it would be randomized for every peer when the deck is shuffled. &lt;/p&gt;

&lt;h4&gt;How Data Is Sent And Received&lt;/h4&gt;

&lt;p&gt;I will usually create a static class called NetworkMessageSender that is responsible for sending various messages. I keep an enumeration of type byte that holds the possible network messages. &lt;/p&gt;

&lt;p&gt;I always send the byte indicating the message type first, so that when the peer receives a byte, it knows how to respond. For example, if the peer receives a CardDealt message, it can pop off a string and a card from the incoming packets. If the card is not intended for the peer, it can simply discard the message. &lt;/p&gt;

&lt;p&gt;Data you want to send is written to a packet writer object. When the data is ready to be sent, you call the SendData method of the LocalGamer object. Depending on how important packet receipt is, you can specify the type of transmission. I use ReliableInOrder during poker because network data is exchanged relatively infrequently. Although there is only one local network gamer, you can use a foreach loop to ensure this code will work on other platforms.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C# 
    &lt;br /&gt;&lt;/b&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SendData()
{
    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (LocalNetworkGamer gamer &lt;span class="kwrd"&gt;in&lt;/span&gt; NetworkSessionManager.Session.LocalGamers)
        gamer.SendData(NetworkSessionManager.PacketWriter, SendDataOptions.ReliableInOrder);
}&lt;/pre&gt;

&lt;p&gt;Specific chunks of data are then sent using various static methods. Each piece of information is written sequentially. The card is serialized into a string format before being sent. The following chunk of code is used to send a card to a player.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C# 
    &lt;br /&gt;&lt;/b&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; DealCards(HoldemPlayer player)
{
    NetworkSessionManager.PacketWriter.Write((&lt;span class="kwrd"&gt;byte&lt;/span&gt;)NetworkMessageType.Deal);
    NetworkSessionManager.PacketWriter.Write(player.Name);
    NetworkSessionManager.PacketWriter.Write(player.Pocket.Card1.Serialize());
    NetworkSessionManager.PacketWriter.Write(player.Pocket.Card2.Serialize());
    SendData();
}&lt;/pre&gt;

&lt;p&gt;On the other side of that, whenever the screen updates, the game is constantly checking for new network data. The following code is part of a method that is called from the game screen’s Update loop.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;C# 
    &lt;br /&gt;&lt;/b&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; UpdateNetworkSession()
{
    NetworkSessionManager.Update();

    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (LocalNetworkGamer localGamer &lt;span class="kwrd"&gt;in&lt;/span&gt; 
        NetworkSessionManager.Session.LocalGamers)
    {
        &lt;span class="kwrd"&gt;while&lt;/span&gt; (localGamer.IsDataAvailable)
        {
            NetworkGamer sender;
            localGamer.ReceiveData(NetworkSessionManager.PacketReader, 
                &lt;span class="kwrd"&gt;out&lt;/span&gt; sender);

            &lt;span class="rem"&gt;// Interpret the first piece of information, the message.&lt;/span&gt;
            NetworkMessageType message = (NetworkMessageType)NetworkSessionManager.PacketReader.ReadByte();

            &lt;span class="rem"&gt;// Determine what to read and what to do based on this message type&lt;/span&gt;
            &lt;span class="kwrd"&gt;switch&lt;/span&gt; (message)
            {
                &lt;span class="rem"&gt;// major snippage&lt;/span&gt;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; NetworkMessageType.Deal: &lt;span class="rem"&gt;// Happens when a card is dealt&lt;/span&gt;
                {
                    &lt;span class="kwrd"&gt;string&lt;/span&gt; playerName = NetworkSessionManager.PacketReader.ReadString();
                    &lt;span class="kwrd"&gt;string&lt;/span&gt; card1 = NetworkSessionManager.PacketReader.ReadString();
                    &lt;span class="kwrd"&gt;string&lt;/span&gt; card2 = NetworkSessionManager.PacketReader.ReadString();

                 _gameplayManager.Players[playerName].Pocket.Set(PlayerPocket.FIRST_CARD_INDEX, &lt;span class="kwrd"&gt;new&lt;/span&gt; 
                    Card(card1));
                 _gameplayManager.Players[playerName].Pocket.Set(PlayerPocket.SECOND_CARD_INDEX, &lt;span class="kwrd"&gt;new&lt;/span&gt; 
                    Card(card2));
                }
                &lt;span class="kwrd"&gt;break&lt;/span&gt;;
            }
        }
    }
}&lt;/pre&gt;

&lt;p&gt;There is a whole bunch of similar code that underlies how the game executes. When a message needs to be sent, the NetworkMessageSender class is used. To determine what happens when a message is received, we look at that ginormous switch statement that gets called in the screen update loop. &lt;/p&gt;

&lt;p&gt;Remember that the host is also a peer and it will receive the very same messages it sends (unless you specify otherwise). Be careful not to double-process messages if they are sent by the host. In some cases you will need to check that the current device is or is not the host. In the sample download, this is achieved just by checking a Boolean value that is set early on in the game.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Building Poker for the Zune, from the ground up, is no small feat! Networked Zune games are far simpler when you have a much more limited set of possible data and messages that could be sent. For example, networked Pong, Battleship or Tetris would be pretty easy compared to poker. Turn-based games on the Zune also provide an interesting challenge in terms of what happens when a Zune drops from the network session.&lt;/p&gt;

&lt;p&gt;This is just a small dip into networked Zune game development. For a deep dive, check out my book, &lt;a href="http://www.tinyurl.com/zunebook"&gt;Zune Game Development using XNA 3.0&lt;/a&gt;, also available on &lt;a href="http://www.apress.com/book/view/9781430218616"&gt;Apress.com as an eBook&lt;/a&gt;. The final chapter is a sprawling 120 pages covering how to build Crazy Eights for the Zune from the ground up.&lt;/p&gt;

&lt;h3&gt;About The Author&lt;/h3&gt;

&lt;p&gt;Dan Waters is an Academic Developer Evangelist at Microsoft, based in Tampa, FL. When he’s not out showing the latest and greatest MS technology to students and faculty, he’s spending time with his wife and young daughter or rocking out on one of his (far too numerous) guitars. Follow Dan on &lt;a href="http://www.twitter.com/danwaters"&gt;Twitter&lt;/a&gt; or check out his &lt;a href="http://www.danwaters.com"&gt;blog&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9582637" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/puzzle/default.aspx">puzzle</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/gaming/default.aspx">gaming</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/hardware/default.aspx">hardware</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/card+and+board+games/default.aspx">card and board games</category></item><item><title>Your Code Sunk My Battleship!</title><link>http://blogs.msdn.com/coding4fun/archive/2008/08/24/8892343.aspx</link><pubDate>Sun, 24 Aug 2008 21:00:14 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8892343</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/8892343.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=8892343</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=8892343</wfw:comment><description>&lt;p&gt;&lt;/p&gt; &lt;span id="c4fmetadata"&gt;   &lt;table cellspacing="0" cellpadding="1" width="100%" border="0"&gt;&lt;tbody&gt;       &lt;tr class="entry_overview"&gt;         &lt;td&gt;&lt;span class="entry_description"&gt;Clarity Battleship is a multi-player game in which players code the &amp;quot;artificial intelligence&amp;quot; needed to command their fleet to victory on the high seas. The game is built using WPF and WCF.&lt;/span&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td colspan="2"&gt;           &lt;div class="entry_author"&gt;Bryan Dougherty&lt;/div&gt;            &lt;div class="entry_company"&gt;&lt;a href="http://blogs.claritycon.com/blogs/bryan_dougherty"&gt;Bryan's Blog&lt;/a&gt;&lt;/div&gt;            &lt;br /&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Difficulty: &lt;/b&gt;&lt;span class="entry_details_input"&gt;Intermediate&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Time Required:&lt;/b&gt; &lt;span class="entry_details_input"&gt;1-3 hours to create your own fleet&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Cost: &lt;/b&gt;&lt;span class="entry_details_input"&gt;Free&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Software: &lt;/b&gt;&lt;span class="entry_details_input"&gt;&lt;a href="http://msdn.com/express/"&gt;Visual Basic or Visual C# Express Editions&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Hardware: &lt;/b&gt;&lt;span class="entry_details_input"&gt;&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Download: &lt;/b&gt;&lt;a href="http://employees.claritycon.com/bdougherty/coding4fun/claritybattleship.zip"&gt;Download&lt;/a&gt;               &lt;ul&gt;&lt;/ul&gt;           &lt;/div&gt;         &lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/span&gt;  &lt;h2&gt;Clarity Battleship&lt;/h2&gt;  &lt;p&gt;At Clarity Consulting we&amp;#8217;re always looking for a little friendly competition. That&amp;#8217;s why a few times a year we hold coding competitions that we call Tech Challenges. I recently organized one based on the classic board game Battleship.&lt;/p&gt;  &lt;p&gt;The flow of the game is based loosely on the board game. The simple goal is to sink all of your opponents&amp;#8217; ships. Since we&amp;#8217;re writing code though, I decided to step up the game play and make it a more interesting, requiring more strategy than luck.&amp;#160; Just like the board game, the battlefield is a grid. Unlike the classic, however, multiple teams can battle at the same time. Each team&amp;#8217;s fleet is assigned to a region of the Battlefield. &lt;/p&gt;  &lt;p&gt;In our tournament we had six teams battle at a time and held one &amp;#8220;Battle Royale&amp;#8221; with eleven teams.&amp;#160; Below you can see a sample screen shot of a game with three teams. Blocks in red indicate damage. The bottom of the screen displays messages broadcast or information about fleets that have been sunk.&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/3a42a85d3afe_9B5D/screenshotLarge.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="154" alt="Screen Shot" src="http://www.coding4fun.net/images/3a42a85d3afe_9B5D/screenshotLarge_thumb.jpg" width="244" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Teams position ships at the beginning of the game and give ships orders to execute including:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Attacking locations on the battlefield &lt;/li&gt;    &lt;li&gt;Performing reconnaissance on an area of the battlefield &lt;/li&gt;    &lt;li&gt;Broadcasting messages to opponents or conspirators via an &amp;#8220;open radio frequency&amp;#8221; (collusion and deception are allowed and encouraged!) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Game play is pseudo turn-based. Teams are notified by the game when their ships are ready to execute an order. Teams are also notified as ships are damaged or sunk. The game ends when only one team remains.&lt;/p&gt;  &lt;h2&gt;Application Architecture&lt;/h2&gt;  &lt;p&gt;Now that you have a feel for the game play, let&amp;#8217;s talk about the code. One reason for building this game was to give myself a fun way to learn more about Windows Communication Foundation (WCF) and Windows Presentation Foundation (WPF), new features of the .NET Framework 3.0.&lt;/p&gt;  &lt;p&gt;WCF provides a new unified mechanism for client-server communication that greatly simplifies that amount of work necessary to by standardizing the way you build your communication pieces. I recommend reading &lt;a href="http://www.code-magazine.com/Article.aspx?QuickID=0705041"&gt;this article&lt;/a&gt; as a good place to start learning about WCF.&lt;/p&gt;  &lt;p&gt;WPF enables richer user interfaces and better integration between developer and designer through the use of XAML. As you can see by my simple (though I think pretty cool) UI, I focused my interest on WCF, but did take advantage of a bit of what WPF has to offer.&lt;/p&gt;  &lt;h3&gt;Overview&lt;/h3&gt;  &lt;p&gt;The Battleship application is divided into three parts. The Battleship.Components project is a shared assembly that contains the classes which manage the communication and the logic of the game as well as class definitions for all of the ships (i.e. AircraftCarrier, Battleship, etc.). The Battleship.Gameboard uses WPF to display the action on the battlefield. Finally, console applications are built by each team wishing to compete.&lt;/p&gt;  &lt;p&gt;The diagram below shows how the pieces fit together.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/3a42a85d3afe_9B5D/ArchitectureDiagramOverview.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="Architecture Diagram - Overview" src="http://www.coding4fun.net/images/3a42a85d3afe_9B5D/ArchitectureDiagramOverview_thumb.jpg" width="244" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;h3&gt;WCF Communication&lt;/h3&gt;  &lt;p&gt;As I mentioned, my focus in development was using WCF to manage the communication between the fleets and the game. I was very interested in exploring the bidirectional communication that can be achieved with WCF because it seemed like a perfect fit for the scenario. A traditional web service can receive messages from clients and send back responses. However, it can&amp;#8217;t originate a message on its own to send to the client. For example, with a web service I could easily have a fleet tell the game about an order to execute (i.e. &amp;#8220;I want my Battleship to attack 7,2&amp;#8221;). However, I can&amp;#8217;t have that web service inform another team that its ship was just sunk.&lt;/p&gt;  &lt;p&gt;With WCF I was able to achieve this without writing a lot of custom code. There is some complexity in the code, but most of that is because my goal was to hide the communication layer from the building of a fleet so that players could simply focus on writing the code to implement their strategy. The following sections will walk through the flow of the communication.&lt;/p&gt;  &lt;h4&gt;Server Side&lt;/h4&gt;  &lt;p&gt;While the Battleship.GameBoard is Windows Forms App, it actually should be considered the server in this application. That&amp;#8217;s because it hosts the WCF service that the Fleets call.&lt;/p&gt;  &lt;p&gt;To define a WCF service, you start by defining the interface for the service. Similar to the WSDL of a web service, this is going to tell consumers what the contract, or inputs and outputs, of the service are. Callers will call the different operations exposed by the service.&lt;/p&gt;  &lt;p&gt;In this application, the IBattleshipGameService interface seen below defines the contract for the service.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;[ServiceContract(CallbackContract=&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(IBattleshipGameServiceCallback))]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IBattleshipGameService
{
    [OperationContract(IsOneWay = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
    &lt;span class="kwrd"&gt;void&lt;/span&gt; RegisterFleet(Fleet fleet);

    [OperationContract(IsOneWay = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
    &lt;span class="kwrd"&gt;void&lt;/span&gt; ExecuteOrder(&lt;span class="kwrd"&gt;string&lt;/span&gt; shipID, Order order);
}&lt;/pre&gt;
&lt;style type="text/css"&gt;












.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The interface shows that there are two methods for consumers to call, RegisterFleet and ExecuteOrder. The OperationContract attribute indicates that these are methods. The IsOneWay parameter of the attributes indicates that no response is sent back to callers. That probably seems straightforward for the RegsterFleet call, but you might expect that ExecuteOrder might return a result.&lt;/p&gt;

&lt;p&gt;Actually what happens is that when a fleet is registered, the service holds on to a channel for calling back to the fleets. And the ExecuteOrder method only queues up an order for processing, but doesn&amp;#8217;t immediately execute it. Before queuing it up, the game logic ensures that there aren&amp;#8217;t already too many pending orders in the queue for the ship. This prevents a team from cheating by blasting the server with orders. We&amp;#8217;ll delve more into how the communication back to the client is achieved later.&lt;/p&gt;

&lt;p&gt;With the interface to the service defined, let&amp;#8217;s turn our attention to a portion of the application configuration file.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.serviceModel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;services&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;service&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Clarity.Battleship.Components.GameSide.BattleshipGameService&amp;quot;&lt;/span&gt; 
                    &lt;span class="attr"&gt;behaviorConfiguration&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;BattleshipGameServiceBehavior&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;endpoint&lt;/span&gt; &lt;span class="attr"&gt;address&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://localhost:8088/BattleshipGameService&amp;quot;&lt;/span&gt;
                  &lt;span class="attr"&gt;binding&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;wsDualHttpBinding&amp;quot;&lt;/span&gt;
                  &lt;span class="attr"&gt;contract&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Clarity.Battleship.Components.GameSide.IBattleshipGameService&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This shows the definition of the service. The contract attribute indicates the service will adhere to the IBattleshipGameService interface. The binding attribute indicates that the WSDualHttpBinding will be used. This is the plumbing that allows both services and clients to send and receive messages.&lt;/p&gt;

&lt;p&gt;With the interface and configuration in place, a concrete implementation has to be built. The BattleshipGameService class provides this. This class implements the IBattleshipGameService interface described above. The actual code for registering a fleet and executing an order are therefore defined here.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,UseSynchronizationContext = &lt;span class="kwrd"&gt;false&lt;/span&gt;)]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; BattleshipGameService : IBattleshipGameService&lt;/pre&gt;

&lt;p&gt;Note the ServiceBehavior attribute and its InstanceContextMode property that decorate the BattleshipGameService class. WCF uses this attribute to decide how to execute the operation when a call comes into the service. In this case, the attributes indicate that the service should run as a singleton. In other words, all calls will be executed by a single instance of the BattleshipGameService. You can further see this in the following code taken from the constructor of the Game class that shows how the service is actually brought to life.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;Uri u = &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;&amp;quot;http://localhost:8088/BattleshipService&amp;quot;&lt;/span&gt;);
_gameHost = &lt;span class="kwrd"&gt;new&lt;/span&gt; ServiceHost(&lt;span class="kwrd"&gt;new&lt;/span&gt; BattleshipGameService(), &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri[] { u });
_gameHost.Open();&lt;/pre&gt;

&lt;p&gt;The ServiceHost (which does what it sounds like and hosts the service) is created by passing in an instance of our service object and the uri for the address of the service (I know the uri seems redundant since it&amp;#8217;s in the config, but as far as I saw I had to use this constructor). Since we know the service host will just use the single instance of the BattleShipGameService, we can track that instance through a private property for convenience and hook its events as seen in the code snippets below.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; BattleshipGameService BattleshipGameService
{
    get
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; (BattleshipGameService)_gameHost.SingletonInstance;
    }
}

&lt;span class="kwrd"&gt;this&lt;/span&gt;.BattleshipGameService.FleetRegistered +=
   &lt;span class="kwrd"&gt;new&lt;/span&gt; FleetRegisteredEventHandler(BattleshipGameService_FleetRegistered);
&lt;span class="kwrd"&gt;this&lt;/span&gt;.BattleshipGameService.OrderExecuted += 
   &lt;span class="kwrd"&gt;new&lt;/span&gt; OrderExecutedEventHandler(BattleshipGameService_OrderExecuted);&lt;/pre&gt;
&lt;style type="text/css"&gt;












.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;












.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;












.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;This allows us to elegantly pass off the calls to the Game class. The service then acts as a simple pass through and leaves the Game class to manage the game.&lt;/p&gt;

&lt;h4&gt;Client Side&lt;/h4&gt;

&lt;p&gt;Now that we&amp;#8217;ve covered the basics of the server side, let&amp;#8217;s look at what happens on the client side. In each console app, a class is created that derives from the FleetCommander class (there are complete directions on how to do this with the downloadable source). The FleetCommander class exposes all of the ships of the Fleet for the team to program against.&lt;/p&gt;

&lt;p&gt;To avoid cheating, (some would call it creative programming) each ship gets a unique identifier set by the Game at startup. That way the Game knows which orders are legitimate. To hide that id and details from the FleetCommander and make a very simple and intuitive interface, the method for executing an order is exposed off of the ship classes. The code snippet below shows how FleetCommander could react to an event indicating that a ship is ready for orders. In this case it is saying that the ship should attack the coordinate at location _targetX, _targetY.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnShipAwaitingOrders(Ship ship, Order lastOrder)
{
      Order orderToExecute = &lt;span class="kwrd"&gt;new&lt;/span&gt; Order();
      orderToExecute.Coordinate = &lt;span class="kwrd"&gt;new&lt;/span&gt; Coordinate(_targetX, _targetY);
      orderToExecute.Type = OrderType.Attack;
      ship.ExecuteOrder(orderToExecute);&lt;/pre&gt;

&lt;p&gt;Under the covers, the Ship.ExecuteOrder method raises an event which is handled by the base FleetCommander class. The FleetCommander calls the appropriate method on a WCF client class which makes the call to the BattleshipGameService.&lt;/p&gt;

&lt;p&gt;A portion of the definition of the WCF client can be seen below. You&amp;#8217;ll see that it is a class that derives from the DuplexClientBase. This class manages the channels that pass messages back and forth. You can think of it as similar to a web service proxy class.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; BattleshipGameServiceClient : 
    System.ServiceModel.DuplexClientBase&amp;lt;IBattleshipGameService&amp;gt;, IBattleshipGameService
{&lt;/pre&gt;

&lt;p&gt;So that covers how messages are sent to the server, but you may be asking yourself &amp;#8220;How did a FleetCommander find out it that a ship was awaiting orders?&amp;#8221; or for that matter &amp;#8220;How does it get notified about anything?&amp;#8221;&lt;/p&gt;

&lt;p&gt;Well, each FleetCommander has an instance of a listener class which receives callbacks from the game service. The way this is set up for the listener is very similarly to how we set up the service. Once again we start with an interface, in this case the IBattleshipGameServiceCallback interface.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IBattleshipGameServiceCallback
{
    [OperationContract(IsOneWay = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
    &lt;span class="kwrd"&gt;void&lt;/span&gt; OnFleetUpdated(Fleet fleet, FleetUpdateReason reason);

    [OperationContract(IsOneWay = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
    &lt;span class="kwrd"&gt;void&lt;/span&gt; OnGameStateChanged(GameInfo gameInfo);

    [OperationContract(IsOneWay=&lt;span class="kwrd"&gt;true&lt;/span&gt;)]
    &lt;span class="kwrd"&gt;void&lt;/span&gt; OnOrderExecuted(&lt;span class="kwrd"&gt;string&lt;/span&gt; shipID, Order lastOrder);

    [OperationContract(IsOneWay = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
    &lt;span class="kwrd"&gt;void&lt;/span&gt; OnMessageReceived(&lt;span class="kwrd"&gt;string&lt;/span&gt; data, Coordinate c);

    [OperationContract(IsOneWay = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
    &lt;span class="kwrd"&gt;void&lt;/span&gt; OnFleetSunk(&lt;span class="kwrd"&gt;string&lt;/span&gt; fleetName);
}&lt;/pre&gt;

&lt;p&gt;Just like before the OperationContract attributes are used to indicate the methods available. And just like before we need a concrete implementation of the interface. Enter the FleetCommanderListener.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; FleetCommanderListener : IBattleshipGameServiceCallback&lt;/pre&gt;

&lt;p&gt;The FleetCommanderListener is used when creating the BattleshipGameServiceClient. As you can see in the constructor definition below, a callbackInstance parameter must be passed in. The BattleshipGameServiceClient can then handle communication to the server via the IBattleshipGameService interface and also listen for communication back that adheres to the IBattleshipGameServiceCallback interface! &lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; BattleshipGameServiceClient(System.ServiceModel.InstanceContext callbackInstance) :
     &lt;span class="kwrd"&gt;base&lt;/span&gt;(callbackInstance)&lt;/pre&gt;

&lt;p&gt;The last little piece of the puzzle is the client configuration file.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.serviceModel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;client&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;endpoint&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Clarity.Battleship.Components.IBattleshipGameService&amp;quot;&lt;/span&gt;
                &lt;span class="attr"&gt;address&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://localhost:8088/BattleshipGameService&amp;quot;&lt;/span&gt;
                &lt;span class="attr"&gt;binding&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;wsDualHttpBinding&amp;quot;&lt;/span&gt;
                &lt;span class="attr"&gt;bindingConfiguration&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;BattleshipBinding&amp;quot;&lt;/span&gt;
                &lt;span class="attr"&gt;contract&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Clarity.Battleship.Components.GameSide.IBattleshipGameService&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;client&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;bindings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="rem"&gt;&amp;lt;!-- configure a binding that support duplex communication --&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;wsDualHttpBinding&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;binding&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;BattleshipBinding&amp;quot;&lt;/span&gt;
                 &lt;span class="attr"&gt;clientBaseAddress&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://localhost:6088/BattleshipGameClient/&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;binding&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;wsDualHttpBinding&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;bindings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;system.serviceModel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;As you can see from the example above, the configuration is fairly straightforward. Just like in the server config, we say we&amp;#8217;re using the wsDualHttpBinding. The one additional piece of info is the clientBaseAddress which tell the server how to call back into the client.&lt;/p&gt;

&lt;h4&gt;The Complete Picture&lt;/h4&gt;

&lt;p&gt;So after reading all of this, you might be thinking &amp;#8220;I thought he said there wasn&amp;#8217;t much custom code needed.&amp;#8221; I think that is still true in terms of the WCF. While certainly not trivial, it really boils down to building a couple interfaces, their concrete implementations, and filling out some config files. Most of the complexity came in was in building out the eventing model to simplify the interface for teams.&lt;/p&gt;

&lt;p&gt;The following diagram helps pull everything together by showing an example of the flow of the communication for execution of an order.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/3a42a85d3afe_9B5D/ArchitectureDiagramFlow.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="135" alt="Architecture Diagram - Flow" src="http://www.coding4fun.net/images/3a42a85d3afe_9B5D/ArchitectureDiagramFlow_thumb.jpg" width="244" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;1. The derived FleetCommander makes calls the ExecuteOrder method on a Ship (i.e. &amp;#8220;I want my Battleship to attack 7,2&amp;#8221;)&lt;/p&gt;

&lt;p&gt;2. The Ship raises an event which is handled by the FleetCommander base class which in turn calls to the BattleshipGameServiceClient&lt;/p&gt;

&lt;p&gt;3. This WCF client class makes the WCF call to execute the order&lt;/p&gt;

&lt;p&gt;4. The single instance of the service raises an event to the Game class with the order information &lt;/p&gt;

&lt;p&gt;5. The Game class which controls all the game flow enqueues the order&lt;/p&gt;

&lt;p&gt;6. After processing an order from the queue, the Game calls the OnOrderExecuted WCF callback which gets invoked on the FleetCommanderListener&lt;/p&gt;

&lt;p&gt;7. Finally the FleetCommanderListener raises an OrderExecuted event to the derived FleetCommander class (i.e. &amp;#8220;Your Battleship&amp;#8217;s attack at 7,2 resulted in a Hit&amp;#8221;) which is turned calls the OnShipAwaitingOrders method and the cycle starts over&lt;/p&gt;

&lt;h3&gt;WPF User Interface&lt;/h3&gt;

&lt;p&gt;The last thing to cover with the architecture is the UI. It is pretty simple, but I wanted to experiment a little with WPF. The Gameboard assembly contains a class called Battlefield that is a WPF Window (comparable to a Winform Form). A Grid control makes up the main component of the gameboard. The grid lent itself to building the UI since everything stretches nicely to fit the screen, regardless of the number of teams competing.&lt;/p&gt;

&lt;p&gt;Once the game starts, the game board is setup by adding rectangles and images to the grid control. Throughout the game, the colors of the rectangles are changed to indicate shots, recon, or hit targets.&lt;/p&gt;

&lt;p&gt;Below is an example of some of the Battlefield code behind in which the rectangle for the location of the order is painted a different color depending on the result of an order.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;Rectangle r = _rectangles[_lastOrderStarted.Order.Coordinate];
&lt;span class="kwrd"&gt;if&lt;/span&gt; (e.Order.Result == OrderResult.ShipHit)
{
    r.Fill = Brushes.Red;
    _rectangleFills[e.Order.Coordinate] = r.Fill;
}
&lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (e.Order.Result == OrderResult.ShipSunk)
{
    r.Fill = Brushes.Red;
    _rectangleFills[e.Order.Coordinate] = r.Fill;
}
&lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (e.Order.Result == OrderResult.Miss)
{
    r.Fill = _rectangleFills[e.Order.Coordinate];
}
&lt;span class="kwrd"&gt;else&lt;/span&gt;
{
    r.Fill = _rectangleFills[e.Order.Coordinate];
}&lt;/pre&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Hopefully you enjoyed this game and learned a little in process. I encourage you to download the code and build your own fleet. The download includes a document called &amp;#8220;Clarity Battleship &amp;#8211; Building a FleetCommander&amp;#8221; which gives you step by step instructions. Feel free to post your own builds here for other people to challenge and good luck with your battles!&lt;/p&gt;

&lt;p&gt;Bryan Dougherty is a Principal with Clarity Consulting, a software development consulting firm based in Chicago, IL. He is an MCP with several years of professional software engineering experience. Bryan earned a B.S. in Computer Science from Northwestern University and writes about topics related to software development on his &lt;a href="http://blogs.claritycon.com/blogs/bryan_dougherty"&gt;blog&lt;/a&gt;.&lt;/p&gt;
&lt;style type="text/css"&gt;












.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;












.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;












.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;












.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;












.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;












.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;












.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8892343" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/gaming/default.aspx">gaming</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/card+and+board+games/default.aspx">card and board games</category></item><item><title>YeahTrivia: Creating a Trivia Server/Client with WPF and WCF</title><link>http://blogs.msdn.com/coding4fun/archive/2007/10/29/5773166.aspx</link><pubDate>Tue, 30 Oct 2007 03:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5773166</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>13</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/5773166.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=5773166</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=5773166</wfw:comment><description>&lt;SPAN id=c4fmetadata&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=1 width="100%" border=0&gt;
&lt;TBODY&gt;
&lt;TR class=entry_overview&gt;
&lt;TD class="" width=50&gt;&lt;IMG height=50 src="http://www.webholstad.com/clarity/coding4fun/yeahtriviathumb.gif" width=50 mce_src="http://www.webholstad.com/clarity/coding4fun/yeahtriviathumb.gif"&gt;&lt;/TD&gt;
&lt;TD class=""&gt;&lt;SPAN class=entry_description&gt;In this article I'll take you along for the ride as I attack the learning curve required to create a fun, interactive application using both the Microsoft Windows Presentation Foundation (WPF) and the Windows Communication Foundation (WCF). Afterwards, you'll have a flexible trivia client/server game ready to play by yourself or against friends, coworkers and your local know-it-all.&amp;nbsp; &lt;EM&gt;And in honor of Halloween, I've included three games of horror movie trivia.&lt;/EM&gt;&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" colSpan=2&gt;
&lt;DIV class=entry_author&gt;Steve Holstad&lt;/DIV&gt;
&lt;DIV class=entry_company&gt;&lt;A href="http://blogs.claritycon.com/blogs/steve_holstad/archive/2007/10/29/3403.aspx" target=_blank mce_href="http://blogs.claritycon.com/blogs/steve_holstad/archive/2007/10/29/3403.aspx"&gt;The Bright Lights&lt;/A&gt;&lt;/DIV&gt;&lt;BR&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Difficulty: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;Advanced&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Time Required:&lt;/B&gt; &lt;SPAN class=entry_details_input&gt;6-10 hours&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Cost: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;Free&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Software: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;Visual Studio Express, 2005, 2008 Beta 2 &lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyID=10CC340B-F857-4A14-83F5-25634C3BF043&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=10CC340B-F857-4A14-83F5-25634C3BF043&amp;amp;displaylang=en"&gt;Microsoft .NET Framework 3.0&lt;/A&gt;&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Hardware: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Download: &lt;/B&gt;&lt;A class="" href="http://www.coding4fun.net/source/YeahTrivia.zip" target=_blank mce_href="http://www.coding4fun.net/source/YeahTrivia.zip"&gt;Download Source&lt;/A&gt; 
&lt;UL&gt;&lt;/UL&gt;&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/SPAN&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3&gt;What can YeahTrivia do for me?&lt;/H3&gt;
&lt;P&gt;Glad you asked. This project started when I decided I wanted to dive headfirst into learning WPF and WCF, without hacking through countless Hello World examples.&amp;nbsp; And I wanted something fun that I could improve over time as my skills developed in these new technologies.&amp;nbsp; In this article I'll take you along for the ride as I attack the learning curve required to create a fun, interactive application using both the Microsoft Windows Presentation Foundation (WPF) and the Windows Communication Foundation (WCF). Afterwards, you'll have a flexible trivia client/server game ready to play by yourself or against friends, coworkers and your local know-it-all.&amp;nbsp; And in honor of Halloween, I've included three games of horror movie trivia.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/YeahTriviaCreatingaTriviaServerandClient_F6C4/YeahTrivia_Client5.jpg" atomicselection="true" mce_href="http://www.coding4fun.net/images/YeahTriviaCreatingaTriviaServerandClient_F6C4/YeahTrivia_Client5.jpg"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=194 src="http://www.coding4fun.net/images/YeahTriviaCreatingaTriviaServerandClient_F6C4/YeahTrivia_Client_thumb1.jpg" width=280 border=0 mce_src="http://www.coding4fun.net/images/YeahTriviaCreatingaTriviaServerandClient_F6C4/YeahTrivia_Client_thumb1.jpg"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;In case you were wondering, the "YeahTrivia" name honors my new bride&amp;nbsp;&amp;amp; her&amp;nbsp;favorite prefix.&amp;nbsp; Think of it as&amp;nbsp;YeeeeaaaaahhTrivia!&lt;/P&gt;
&lt;H3&gt;Basic Setup&lt;/H3&gt;
&lt;P&gt;This demo project was built using Visual Studio 2008 Beta 2, and is based on the Microsoft .NET Framework version 3.0.&amp;nbsp; The game is fed by a small windows app that acts as a game server, providing game selection, user&amp;nbsp;registration, question loading, response times, chat messaging&amp;nbsp;and scorekeeping.&amp;nbsp; The server loads a game by reading a predefined XML format, which we will look at a bit later.&amp;nbsp; This dynamic load lets anyone create their own flavor of trivia game, with any number of questions.&lt;/P&gt;
&lt;P&gt;The server app exposes one WCF endpoint, a wsDualHttpBinding channel that supports duplex (two-way) communication between the server and any number of game clients.&amp;nbsp; Clients attach themselves to this endpoint and provide a callback address to the server.&amp;nbsp; The server saves an instance of this callback channel and uses each client's instance to&amp;nbsp;contact the clients en masse during general game flow.&amp;nbsp; Enough talk, here's how to build one yourself.&lt;/P&gt;
&lt;H3&gt;Trivia Common and WCF Service Interfaces&lt;/H3&gt;
&lt;P&gt;The TriviaCommon project provides both the server and client projects access to shared objects.&amp;nbsp; To keep things simple the Common project only contains two classes:&lt;/P&gt;
&lt;P&gt;Constants.cs defines the AnswerItem enumeration, which gives easy access to the five answer options (None, A, B, C, D), and the QuestionItem struct.&amp;nbsp; This structure is delivered to the client and contains question text, answer text, and the correct answer object of type AnswerItem.&amp;nbsp; Notice that objects being directly passed over the wire need to be marked with the [DataContract] attribute.&lt;/P&gt;
&lt;P&gt;The second class, Interfaces.cs is where our WCF fun begins.&amp;nbsp; Take a look:&lt;/P&gt;&lt;STRONG&gt;C#:&lt;/STRONG&gt;&lt;BR&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Collections.Generic;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.ServiceModel;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Text;

&lt;SPAN class=kwrd&gt;namespace&lt;/SPAN&gt; Trivia.Common
{
    &lt;SPAN class=preproc&gt;#region&lt;/SPAN&gt; Interfaces

    &lt;SPAN class=preproc&gt;#region&lt;/SPAN&gt; Service Interface

    &lt;SPAN class=rem&gt;/// &amp;lt;summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// Interface that defines Trivia service contract.&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;/summary&amp;gt;&lt;/SPAN&gt;
    [ServiceContract(CallbackContract = &lt;SPAN class=kwrd&gt;typeof&lt;/SPAN&gt;(ITriviaCallback))]
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;interface&lt;/SPAN&gt; ITrivia
    {
        [OperationContract(IsOneWay = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;)]
        &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; RegisterUser(&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; userName);

        [OperationContract(IsOneWay = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;)]
        &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; AcceptAnswer(&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; userName, &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; answerValue);

        [OperationContract(IsOneWay = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;)]
        &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; ChatPublish(&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; userName, &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; message);
    }

    &lt;SPAN class=preproc&gt;#endregion&lt;/SPAN&gt; Service Interface

    &lt;SPAN class=preproc&gt;#region&lt;/SPAN&gt; Client Callback Interface

    &lt;SPAN class=rem&gt;/// &amp;lt;summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// Interface that defines Trivia client callback contract.&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;/// &amp;lt;/summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;interface&lt;/SPAN&gt; ITriviaCallback
    {        
        [OperationContract(IsOneWay = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;)]
        &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; OnGameStart(&lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; questionCount);

        [OperationContract(IsOneWay = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;)]
        &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; OnGameEnd();

        [OperationContract(IsOneWay = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;)]
        &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; OnUserRegistered(&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; userName);

        [OperationContract(IsOneWay = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;)]
        &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; OnPublishChat(&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; userName, &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; chatMessage);

        [OperationContract(IsOneWay = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;)]
        &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; OnQuestionLoad(&lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; questionIndex, QuestionItem questionItem);

        [OperationContract(IsOneWay = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;)]
        &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; OnQuestionEnd();

        [OperationContract(IsOneWay = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;)]
        &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; OnQuestionStatusUpdate(Int64 questionTimeRemaining);

        [OperationContract(IsOneWay = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;)]
        &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; OnScoreboardUpdate(Dictionary&amp;lt;&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;, Int64&amp;gt; scoreboard);

        [OperationContract(IsOneWay = &lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;)]
        &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; OnGameServerStopped();
    }

    &lt;SPAN class=preproc&gt;#endregion&lt;/SPAN&gt; Client Callback Interface

    &lt;SPAN class=preproc&gt;#endregion&lt;/SPAN&gt; Interfaces
}
&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;&lt;STRONG&gt;VB:&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Imports&lt;/SPAN&gt; System
&lt;SPAN class=kwrd&gt;Imports&lt;/SPAN&gt; System.Collections.Generic
&lt;SPAN class=kwrd&gt;Imports&lt;/SPAN&gt; System.ServiceModel
&lt;SPAN class=kwrd&gt;Imports&lt;/SPAN&gt; System.Text

&lt;SPAN class=kwrd&gt;Namespace&lt;/SPAN&gt; Trivia.Common

&lt;SPAN class=preproc&gt;#Region&lt;/SPAN&gt; &lt;SPAN class=str&gt;"Interfaces"&lt;/SPAN&gt;

&lt;SPAN class=preproc&gt;#Region&lt;/SPAN&gt; &lt;SPAN class=str&gt;"Service Interface"&lt;/SPAN&gt;
    
    &lt;SPAN class=rem&gt;''' &amp;lt;summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;''' Interface that defines Trivia service contract.&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;''' &amp;lt;/summary&amp;gt;&lt;/SPAN&gt;
    &amp;lt;ServiceContract(CallbackContract:=&lt;SPAN class=kwrd&gt;GetType&lt;/SPAN&gt;(ITriviaCallback))&amp;gt; _
    &lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Interface&lt;/SPAN&gt; ITrivia
        &amp;lt;OperationContract(IsOneWay:=&lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;)&amp;gt; _
        &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; RegisterUser(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; userName &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;)

        &amp;lt;OperationContract(IsOneWay:=&lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;)&amp;gt; _
        &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; AcceptAnswer(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; userName &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; answerValue &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;)

        &amp;lt;OperationContract(IsOneWay:=&lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;)&amp;gt; _
        &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; ChatPublish(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; userName &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; message &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;)
    &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Interface&lt;/SPAN&gt;
        
&lt;SPAN class=preproc&gt;#End Region&lt;/SPAN&gt;

&lt;SPAN class=preproc&gt;#Region&lt;/SPAN&gt; &lt;SPAN class=str&gt;"Client Callback Interface"&lt;/SPAN&gt;

    &lt;SPAN class=rem&gt;''' &amp;lt;summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;''' Interface that defines Trivia client callback contract.&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;''' &amp;lt;/summary&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=rem&gt;''' &amp;lt;remarks&amp;gt;&amp;lt;/remarks&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Interface&lt;/SPAN&gt; ITriviaCallback
        &amp;lt;OperationContract(IsOneWay:=&lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;)&amp;gt; _
      &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; OnGameStart(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; questionCount &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Integer&lt;/SPAN&gt;)

        &amp;lt;OperationContract(IsOneWay:=&lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;)&amp;gt; _
        &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; OnGameEnd()

        &amp;lt;OperationContract(IsOneWay:=&lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;)&amp;gt; _
        &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; OnUserRegistered(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; userName &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;)

        &amp;lt;OperationContract(IsOneWay:=&lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;)&amp;gt; _
        &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; OnPublishChat(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; userName &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; chatMessage &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;)

        &amp;lt;OperationContract(IsOneWay:=&lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;)&amp;gt; _
        &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; OnQuestionLoad(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; questionIndex &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Integer&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; questionItem &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; QuestionItem)

        &amp;lt;OperationContract(IsOneWay:=&lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;)&amp;gt; _
        &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; OnQuestionEnd()

        &amp;lt;OperationContract(IsOneWay:=&lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;)&amp;gt; _
        &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; OnQuestionStatusUpdate(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; questionTimeRemaining &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Long&lt;/SPAN&gt;)

        &amp;lt;OperationContract(IsOneWay:=&lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;)&amp;gt; _
        &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; OnScoreboardUpdate(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; scoreboard &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Dictionary(Of &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;Long&lt;/SPAN&gt;))

        &amp;lt;OperationContract(IsOneWay:=&lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;)&amp;gt; _
        &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; OnGameServerStopped()

    &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Interface&lt;/SPAN&gt;

&lt;SPAN class=preproc&gt;#End Region&lt;/SPAN&gt;

&lt;SPAN class=preproc&gt;#End Region&lt;/SPAN&gt;

&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Namespace&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;A few items of interest here.&amp;nbsp; Notice we're importing the System.ServiceModel namespace.&amp;nbsp; This is the key assembly when using WCF, so don't forget to add a reference to your project.&amp;nbsp; The first interface, ITrivia, defines the operations the server is required to implement, which handle basic user actions: Register a team, accept an answer and accept a chat message.&amp;nbsp; Easy.&lt;/P&gt;
&lt;P&gt;The second interface, cleverly named ITriviaCallback, lays out the callback contract a client must fulfill in order to play nicely with our server.&amp;nbsp; The operations listed here describe events the server will publish.&amp;nbsp; These aren't actual events, but the naming convention "OnX..." helps you remember that these are server published activities.&lt;/P&gt;
&lt;P&gt;Notice that the [OperationContract] attribute notifies WCF that each method is part of a service contract.&amp;nbsp; The IsOneWay flag gives us "fire-and-forget" behavior (the app shouldn't wait around for a response).&amp;nbsp; So now that the common objects are ready, let's move on to...&lt;/P&gt;
&lt;H3&gt;Building the Trivia Server&lt;/H3&gt;
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/YeahTriviaCreatingaTriviaServerandClient_F6C4/YeahTrivia_Server1.jpg" atomicselection="true" mce_href="http://www.coding4fun.net/images/YeahTriviaCreatingaTriviaServerandClient_F6C4/YeahTrivia_Server1.jpg"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=202 src="http://www.coding4fun.net/images/YeahTriviaCreatingaTriviaServerandClient_F6C4/YeahTrivia_Server.jpg" width=240 border=0 mce_src="http://www.coding4fun.net/images/YeahTriviaCreatingaTriviaServerandClient_F6C4/YeahTrivia_Server.jpg"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;The YeahTrivia Server is a simple utility app, but don't let&amp;nbsp;the plain looks fool you; I thought about calling this the BrainStumper Pumper, but this is a family site.&amp;nbsp; This app&amp;nbsp;lets a user (anyone acting as game admin)&amp;nbsp;start the service, select the desired game, await team registrations, and then start the game.&amp;nbsp; If this were to become a larger scale project, I would make this an IIS hosted service that manages multiple games and provides more autonomy.&amp;nbsp; Until those sports bar royalty checks start rolling in, however, a utility app will do just fine.&lt;/P&gt;
&lt;P&gt;The only form, GameServerDashboard, simply provides user interaction with the GameServer class.&amp;nbsp; On startup, the form&amp;nbsp;inits an instance of GameServer and tells it to start the service.&amp;nbsp; It also loads all trivia question sets from the Games directory, and displays them in the list.&lt;/P&gt;
&lt;P&gt;GameServer is the brain behind YeahTrivia.&amp;nbsp;The attributes below set up the GameServer for action:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;C#:&lt;/STRONG&gt;&lt;BR&gt;&lt;PRE class=csharpcode&gt;[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant
        ,InstanceContextMode = InstanceContextMode.Single)]
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; GameServer : ITrivia&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;VB:&lt;/STRONG&gt;&lt;BR&gt;&lt;PRE class=csharpcode&gt;&amp;lt;ServiceBehavior(ConcurrencyMode:=ConcurrencyMode.Reentrant, InstanceContextMode:=InstanceContextMode.&lt;SPAN class=kwrd&gt;Single&lt;/SPAN&gt;)&amp;gt; _
    &lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Class&lt;/SPAN&gt; GameServer
        &lt;SPAN class=kwrd&gt;Implements&lt;/SPAN&gt; ITrivia&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;ConcurrencyMode.Reentrant prevents deadlocks between the&amp;nbsp;apps&amp;nbsp;by stating that while this service is single-threaded, callbacks are allowed to invoke&amp;nbsp;new&amp;nbsp;operations.&lt;/P&gt;
&lt;P&gt;InstanceContextMode.Single sets the service as a singleton, so that all messages are delivered to the same object instance.&lt;/P&gt;
&lt;P&gt;These are advanced topics if you're new to WCF, so I'll include some links at the end that helped clarify some of this for me.&amp;nbsp; Let's keep moving forward by looking at a few activities of the game server:&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Start the Service:&lt;/EM&gt;&amp;nbsp; Passes in the configured base address as a Uri, inits and opens a new ServiceHost.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;C#:&lt;/STRONG&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; StartService()
{
&lt;SPAN class=rem&gt;   // Set base address and open service host&lt;/SPAN&gt;
   Uri baseAddress = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Uri(ConfigurationManager.AppSettings[CONFIG_KEY_BASEURI]);
   _serviceHost = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; ServiceHost(&lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; GameServer(), baseAddress);
   _serviceHost.Open();
}&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;&lt;STRONG&gt;VB:&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;  &lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; StartService()
     &lt;SPAN class=rem&gt;'Set base address and open service host&lt;/SPAN&gt;
     &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; baseAddress &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; Uri(ConfigurationManager.AppSettings(CONFIG_KEY_BASEURI))
     _serviceHost = &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; ServiceHost(&lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; GameServer(), baseAddress)
     _serviceHost.Open()
  &lt;SPAN class=kwrd&gt;End Sub&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;&lt;EM&gt;&lt;/EM&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Register a new team:&lt;/EM&gt;&amp;nbsp;Saves off the callback, adds it to the callback collection and scoreboard containers, notifies the user of a successful registration, and notifies all game clients of the new team.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;C#:&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt; &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; RegisterUser(&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; userName)
 {
     _currentCallback = OperationContext.Current.GetCallbackChannel&amp;lt;ITriviaCallback&amp;gt;();

     &lt;SPAN class=rem&gt;// Store callback&lt;/SPAN&gt;
     &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (!_callbacks.ContainsKey(userName))
     {
         _callbacks.Add(userName, _currentCallback);
         _scoreboard.Add(userName, 0);
&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;         &lt;SPAN class=rem&gt;// Notify user of registration&lt;/SPAN&gt;
         _currentCallback.OnUserRegistered(userName);
&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;         &lt;SPAN class=rem&gt;// Notify clients of new user&lt;/SPAN&gt;
         &lt;SPAN class=kwrd&gt;foreach&lt;/SPAN&gt; (&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; userKey &lt;SPAN class=kwrd&gt;in&lt;/SPAN&gt; _callbacks.Keys)
         {
            _currentCallback = _callbacks[userKey];
            _currentCallback.OnPublishChat(GAME_USERKEY, &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;.Format(FORMAT_USER_REGISTERED, userName));
         }                
     }
     &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;
     {
         &lt;SPAN class=rem&gt;// User already registered, throw exception&lt;/SPAN&gt;
         &lt;SPAN class=kwrd&gt;throw&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Exception(ERROR_USER_ALREADY_EXISTS);
     }
 }&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;&lt;STRONG&gt;VB:&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; RegisterUser(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; userName &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;) &lt;SPAN class=kwrd&gt;Implements&lt;/SPAN&gt; ITrivia.RegisterUser
   _currentCallback = OperationContext.Current.GetCallbackChannel(Of ITriviaCallback)()

   &lt;SPAN class=rem&gt;'Store callback&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Not&lt;/SPAN&gt; _callbacks.ContainsKey(userName) &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;
      _callbacks.Add(userName, _currentCallback)
      _scoreboard.Add(userName, 0)

      &lt;SPAN class=rem&gt;'Notify user of registration&lt;/SPAN&gt;
      _currentCallback.OnUserRegistered(userName)

      &lt;SPAN class=rem&gt;'Notify clients of new user&lt;/SPAN&gt;
      &lt;SPAN class=kwrd&gt;For&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Each&lt;/SPAN&gt; userKey &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;In&lt;/SPAN&gt; _callbacks.Keys
         _currentCallback = _callbacks(userKey)
         _currentCallback.OnPublishChat(GAME_USERKEY, &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;.Format(FORMAT_USER_REGISTERED, userName))
      &lt;SPAN class=kwrd&gt;Next&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;Else&lt;/SPAN&gt;
      &lt;SPAN class=rem&gt;'User already registered, throw exception&lt;/SPAN&gt;
      &lt;SPAN class=kwrd&gt;Throw&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; Exception(ERROR_USER_ALREADY_EXISTS)
   &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;End Sub&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;You can start to see how the server is able to handle incoming calls and process them back to the clients using the duplex channel.&amp;nbsp; I'll leave the rest of the server actions for you to examine on your own.&lt;/P&gt;
&lt;H3&gt;Building the Game Client (WCF) &lt;/H3&gt;
&lt;P&gt;Address, Binding, Contract.&amp;nbsp; These are the ABC's of WCF.&amp;nbsp; The client's app.config file handles connecting to the service and specifying the channel and contract used to interact with it.&amp;nbsp; Examine the client portion of the client .config:&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;client&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;endpoint&lt;/SPAN&gt; &lt;SPAN class=attr&gt;address&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="http://localhost:8088/Trivia"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;binding&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="wsDualHttpBinding"&lt;/SPAN&gt;
      &lt;SPAN class=attr&gt;bindingConfiguration&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="WSDualHttpBinding_ITrivia"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;contract&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="Trivia.Common.ITrivia"&lt;/SPAN&gt;
      &lt;SPAN class=attr&gt;name&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="WSDualHttpBinding_ITrivia"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;endpoint&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;client&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;The address points to the exposed service endpoint.&amp;nbsp; The binding sets the channel as "wsDualHttpBinding" (our http duplex channel).&amp;nbsp; The bindingConfiguration attribute is an optional&amp;nbsp;pointer to another group of configurations for the binding, and finally, the contract sets the interface with which our client will be interacting.&lt;/P&gt;
&lt;P&gt;Next it's time to generate a proxy class.&amp;nbsp;&amp;nbsp;Memorize this: Svcutil.exe is your friend.&amp;nbsp; The client needs a proxy class that it can use to interact with the service model.&amp;nbsp; The&amp;nbsp;utility is a bit tricky at first, because of the wealth of optional flags, but stick with it, it's better than coding the proxy class by hand!&amp;nbsp; You can generate your client code by starting the service and running a command line similar to this:&lt;/P&gt;&lt;PRE class=csharpcode&gt;svcutil /language:cs /out:ServerProxy.cs &lt;A href="http://localhost:8088/Trivia" mce_href="http://localhost:8088/Trivia"&gt;http://localhost:8088/Trivia&lt;/A&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;Add the generated class to the client project and you can begin to interact with the service.&amp;nbsp; The svcutil is available as part of the Windows SDK.&amp;nbsp; Check out the referenced site below&amp;nbsp;for more information on this handy utility.&lt;/P&gt;
&lt;H3&gt;Building the Game Client (WPF)&lt;/H3&gt;
&lt;P&gt;Building the WPF portion of the client app was really a learning experience, and it will&amp;nbsp;be the&amp;nbsp;priority for me to improve in a later version.&amp;nbsp; Learning to program in XAML markup can seem daunting, and it requires a large paradigm shift on your part in order to grasp the new concepts.&amp;nbsp;&amp;nbsp;Microsoft Expression is powerful tool for XAML work, but this time I coded all of the XAML by hand in order to fully see what was taking place inside.&lt;/P&gt;
&lt;P&gt;A deep discussion of WPF is beyond the scope of this article, but take a look at the example code to get an idea of the layout.&amp;nbsp; An excellent book to start with is &lt;U&gt;WPF Unleashed&lt;/U&gt; by Adam Nathan.&amp;nbsp; An easy read (for a programming book), and solid examples to get you rolling.&lt;/P&gt;
&lt;P&gt;I've set up the client using&amp;nbsp;a instance of the Window class, which is shown below:&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Window&lt;/SPAN&gt; &lt;SPAN class=attr&gt;x:Class&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="Trivia.Client.GameClient"&lt;/SPAN&gt;
    &lt;SPAN class=attr&gt;xmlns&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;/SPAN&gt;
    &lt;SPAN class=attr&gt;xmlns:x&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="http://schemas.microsoft.com/winfx/2006/xaml"&lt;/SPAN&gt;
    &lt;SPAN class=attr&gt;Title&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="YeahTrivia"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;MinHeight&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="620"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;MinWidth&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="620"&lt;/SPAN&gt; 
    &lt;SPAN class=attr&gt;WindowStartupLocation&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="CenterScreen"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;WindowState&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="Normal"&lt;/SPAN&gt;  &lt;SPAN class=attr&gt;Style&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="{DynamicResource MainWindowStyle}"&lt;/SPAN&gt;
    &lt;SPAN class=attr&gt;Background&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="{DynamicResource MainWindowBackgroundBrush}"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;The window class sets up the outermost container of the app, and includes two default namespaces.&amp;nbsp; I've also set a few other properties here: a min height and width, window startup location &amp;amp; state, and two styling attributes set by dynamic resources.&lt;/P&gt;
&lt;P&gt;Resources are a great way to further separate form &amp;amp; function, allowing a programmer to handle the behavior of an app, while a designer can work simultaneously on the look, all without stepping on too many toes.&amp;nbsp; As a 2.0 task for this project, I would remove all inline styling and move them into resource dictionaries.&amp;nbsp; A dictionary contains styles and control templates (a skin) that can be loaded &amp;amp; switched&amp;nbsp;at runtime.&lt;/P&gt;
&lt;P&gt;ResourceDictionaries are linked to your XAML in the App.Xaml file.&amp;nbsp; Once you've set up the reference, the&amp;nbsp;example above show&amp;nbsp;how to&amp;nbsp;reference the current dictionary:&amp;nbsp; The Background and Style&amp;nbsp;properties are set as dynamic resources by naming&amp;nbsp;the Keys specified in the&amp;nbsp;ResourceDictionary (DefaultResources.xaml):&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;LinearGradientBrush&lt;/SPAN&gt; &lt;SPAN class=attr&gt;x:Key&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="MainWindowBackgroundBrush"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;StartPoint&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;=".45,.45"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;EndPoint&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;=".55,.55"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;SpreadMethod&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="Reflect"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;GradientStop&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Offset&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="0"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Color&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="DodgerBlue"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;/&amp;gt;&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;GradientStop&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Offset&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;=".8"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Color&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="DarkSlateBlue"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;/&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;LinearGradientBrush&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;

&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Style&lt;/SPAN&gt; &lt;SPAN class=attr&gt;TargetType&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="{x:Type Window}"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;x:Key&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="MainWindowStyle"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
   &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Setter&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Property&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="FontFamily"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="Trebuchet MS"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;/&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;Style&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;Not quite as easy as CSS, but for a Forms project, it's a nice feature.&amp;nbsp; The sample ResourceDictionary includes a button control template for all of my buttons, based on Rob Eisenberg's excellent article (link below).&lt;/P&gt;
&lt;P&gt;One other interesting feature to point out: Take a look at the code-behind class MarshalToUIThread method, which accepts a SendOrPostCallback parameter.&amp;nbsp; This is where&amp;nbsp;the client is transferring actions from the sync thread back to the UI thread.&amp;nbsp; In each interface method implementation (OnX..), you can see how I wrap any UI-directed code and assign&amp;nbsp;it to the postCallback field.&amp;nbsp; Passing this to the MarshalToUIThread method simply issues a SynchronizationContext.Post call, and the UI thread executes as expected.&lt;/P&gt;
&lt;H3&gt;Creating a New Trivia Game (XML)&lt;/H3&gt;
&lt;P&gt;New trivia games can be added at any time using&amp;nbsp;the simple XML format shown here.&amp;nbsp; After installing the server application, simply drop the new .XML file into the Games directory ([Server Install Location]\Yeah Trivia Server\Games).&amp;nbsp; This demo comes pre-loaded with Geek Trivia, and&amp;nbsp;a special Halloween Trivia version in case you're feeling festive.&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;TriviaQuestionDataSet&lt;/SPAN&gt; &lt;SPAN class=attr&gt;xmlns&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="http://tempuri.org/TriviaQuestionDataSet.xsd"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;TriviaQuestion&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;QuestionText&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;Name the highest grossing Monty Python creation.&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;QuestionText&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextA&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;A) Holy Grail&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextA&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextB&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;B) The Life of Brian&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextB&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextC&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;C) Shrubbery&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextC&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextD&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;D) The Meaning of Life&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextD&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;CorrectAnswerKey&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;A&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;CorrectAnswerKey&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;TriviaQuestion&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;TriviaQuestion&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;QuestionText&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;Ferris Bueller's best friend was _________.&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;QuestionText&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextA&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;A) Sloane Peterson&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextA&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextB&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;B) Edward R. Rooney&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextB&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextC&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;C) Charlie Sheen&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextC&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextD&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;D) Cameron Frye&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;AnswerTextD&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;CorrectAnswerKey&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;D&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;CorrectAnswerKey&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;TriviaQuestion&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;TriviaQuestionDataSet&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: consolas, "Courier New", courier, monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;H3&gt;It's Time to Play YeahTrivia&lt;/H3&gt;
&lt;P&gt;Install both the Server and Client applications.&amp;nbsp; First, fire up the server, and then start your game client(s).&amp;nbsp; Once everyone has registered a team, select your game and hit "Start Game".&amp;nbsp;&amp;nbsp;&amp;nbsp; You're off...&lt;/P&gt;
&lt;H3&gt;Game Over&lt;/H3&gt;
&lt;P&gt;So there you have it.&amp;nbsp; We've seen&amp;nbsp;how WCF manages communication between objects, extracting complicated service protocols away from your code.&amp;nbsp; And just a&amp;nbsp;small subset of the WPF functionality has shown us&amp;nbsp;how quickly a rich, XAML-based UI can come together.&amp;nbsp; And maybe, just maybe, you've learned why a CD is 74 minutes long... but I'm not telling.&lt;/P&gt;
&lt;P&gt;I challenge you to improve on this initial version of YeahTrivia:&amp;nbsp; Crack open the XAML and add animations, images, video, music &amp;amp; more.&amp;nbsp;&amp;nbsp;Create a self-maintaining server to run multiple games at once.&amp;nbsp; Add a High Score storage system.&amp;nbsp; Extend the WCF settings to enable other communication channels.&amp;nbsp; Add a new skin.&amp;nbsp;Create new question files to share with us.&amp;nbsp;&amp;nbsp;Whatever you do, have fun and&amp;nbsp;go nuts.&amp;nbsp; YeahCoding4Fun.&lt;/P&gt;
&lt;P&gt;Download &lt;A href="http://employees.claritycon.com/sholstad/blog/Coding4Fun/YeahTrivia/YeahTrivia.zip" mce_href="http://employees.claritycon.com/sholstad/blog/Coding4Fun/YeahTrivia/YeahTrivia.zip"&gt;source files&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Download &lt;A href="http://employees.claritycon.com/sholstad/blog/Coding4Fun/YeahTrivia/" mce_href="http://employees.claritycon.com/sholstad/blog/Coding4Fun/YeahTrivia/"&gt;compiled demo (C# and VB)&lt;/A&gt;&lt;/P&gt;
&lt;H3&gt;About The Author&lt;/H3&gt;
&lt;P&gt;Steve Holstad works as a software consultant for Clarity Consulting in Chicago.&amp;nbsp; He blogs at &lt;A href="http://blogs.claritycon.com/blogs/steve_holstad/default.aspx" target=_blank mce_href="http://blogs.claritycon.com/blogs/steve_holstad/default.aspx"&gt;The Bright Lights&lt;/A&gt;, and is available via email at &lt;A href="mailto:sholstad@claritycon.com" mce_href="mailto:sholstad@claritycon.com"&gt;sholstad@claritycon.com&lt;/A&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3&gt;References&lt;/H3&gt;
&lt;P&gt;&lt;A href="http://wcf.netfx3.com/" target=_blank mce_href="http://wcf.netfx3.com/"&gt;wcf.netfx3.com/&lt;/A&gt;&lt;BR&gt;&lt;A href="http://wpf.netfx3.com/" target=_blank mce_href="http://wpf.netfx3.com/"&gt;wpf.netfx3.com/&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/ms733133.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/ms733133.aspx"&gt;Generating a client proxy class&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/system.servicemodel.concurrencymode.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/system.servicemodel.concurrencymode.aspx"&gt;ConcurrencyMode&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/ms733133.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms733133.aspx"&gt;SvcUtil.exe Tutorial&lt;/A&gt; &lt;BR&gt;&lt;A href="http://devlicio.us/blogs/rob_eisenberg/archive/2006/12/03/net-3-0-crash-course-part-6-wpf-styles-and-control-templates.aspx" target=_blank mce_href="http://devlicio.us/blogs/rob_eisenberg/archive/2006/12/03/net-3-0-crash-course-part-6-wpf-styles-and-control-templates.aspx"&gt;Rob Eisenberg's WPF control template&lt;/A&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Special thanks to &lt;A href="https://blogs.claritycon.com/blogs/bryan_dougherty/default.aspx" target=_blank mce_href="https://blogs.claritycon.com/blogs/bryan_dougherty/default.aspx"&gt;Bryan Dougherty&lt;/A&gt; for the WCF jumpstart, &lt;A href="https://blogs.claritycon.com/blogs/kevin_marshall/default.aspx" target=_blank mce_href="https://blogs.claritycon.com/blogs/kevin_marshall/default.aspx"&gt;Kevin Marshall&lt;/A&gt; for the Halloween Trivia and &lt;A href="http://blogs.techrepublic.com.com/geekend/index.php?cat=400&amp;amp;submit=view" target=_blank mce_href="http://blogs.techrepublic.com.com/geekend/index.php?cat=400&amp;amp;submit=view"&gt;Jay Garmon&lt;/A&gt;, creator of TechRepublic's Geek Trivia.&lt;/EM&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5773166" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/windows+miscellaneous/default.aspx">windows miscellaneous</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/arcade/default.aspx">arcade</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/windows/default.aspx">windows</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/gaming/default.aspx">gaming</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/card+and+board+games/default.aspx">card and board games</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/halloween/default.aspx">halloween</category></item><item><title>Designing FreeCell using Expression and Visual Studio Toolsets</title><link>http://blogs.msdn.com/coding4fun/archive/2006/10/31/912523.aspx</link><pubDate>Tue, 31 Oct 2006 16:49:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:912523</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/912523.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=912523</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=912523</wfw:comment><description>&lt;SPAN id=c4fmetadata&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=1 width="100%" border=0&gt;
&lt;TBODY&gt;
&lt;TR class=entry_overview&gt;
&lt;TD class="" width=50&gt;&amp;nbsp;&lt;/TD&gt;
&lt;TD class=""&gt;&lt;SPAN class=entry_description&gt;This article re-creates the game FreeCell using the January CTP and Visual Studio 2005 Express.&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" colSpan=2&gt;
&lt;DIV class=entry_author&gt;Unni Ravindranathan&lt;/DIV&gt;
&lt;DIV class=entry_company&gt;&lt;A href="http://blogs.msdn.com/unnir/"&gt;Unni's Blog&lt;/A&gt;&lt;/DIV&gt;&lt;BR&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Difficulty: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;Intermediate&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Time Required:&lt;/B&gt; &lt;SPAN class=entry_details_input&gt;3-6 hours&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Cost: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;$50-$100&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Software: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;&lt;A href="http://msdn.com/express/"&gt;Visual Studio Express Editions&lt;/A&gt;, &lt;A href="http://www.microsoft.com/products/expression/en/interactive_designer/default.mspx"&gt;Microsoft Expression Interactive Designer&lt;/A&gt;, &lt;A href="http://msdn.microsoft.com/windowsvista/downloads/products/getthebeta/default.aspx%22"&gt;Windows Vista, .NET Framework 3.0 Runtime and Windows SDK Downloads&lt;/A&gt;&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Hardware: &lt;/B&gt;&lt;SPAN class=entry_details_input&gt;&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=entry_details&gt;&lt;B&gt;Download: &lt;/B&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://download.microsoft.com/download/4/1/e/41e8f2c1-1bf7-419f-b31b-06122d090a49/FreeCell_CS_VISTA.msi"&gt;C# Download&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/SPAN&gt;
&lt;P&gt;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 &lt;A href="http://msdn.microsoft.com/windowsvista/getthebeta/default.aspx" mce_href="http://msdn.microsoft.com/windowsvista/getthebeta/default.aspx"&gt;January CTP&lt;/A&gt; 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! &lt;/P&gt;
&lt;H4&gt;About the technology used&lt;/H4&gt;
&lt;P&gt;"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. &lt;/P&gt;
&lt;P&gt;"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. &lt;/P&gt;
&lt;P&gt;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 &lt;A href="http://www.microsoft.com/expression" mce_href="http://www.microsoft.com/expression"&gt;http://www.microsoft.com/expression&lt;/A&gt;. &lt;/P&gt;
&lt;H4&gt;Creating the Game&lt;/H4&gt;
&lt;P&gt;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. &lt;/P&gt;
&lt;P&gt;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). &lt;/P&gt;
&lt;P&gt;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: &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Card.cs defines &lt;B&gt;Card&lt;/B&gt;, which is your regular card data structure. &lt;/LI&gt;
&lt;LI&gt;Cell.cs defines &lt;B&gt;Cell&lt;/B&gt;. FreeCell has two kinds of cells: &lt;B&gt;Home&lt;/B&gt; and &lt;B&gt;Free&lt;/B&gt;. &lt;/LI&gt;
&lt;LI&gt;GameModel.cs defines &lt;B&gt;GameModel,&lt;/B&gt; which is the main game engine and holds the data structures for the various card stacks and cells. &lt;/LI&gt;
&lt;LI&gt;RandomCardGenerator.cs defines a helper class that helps generate cards in random order using &lt;B&gt;Enumeration&lt;/B&gt; – I brought this type in from a previous card game I wrote. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;B&gt;GameModel&lt;/B&gt; exposes all the data-structures as properties, such as &lt;B&gt;HomeCells&lt;/B&gt; (which is a collection of home cells), &lt;B&gt;FreeCells&lt;/B&gt; and &lt;B&gt;CardStacks&lt;/B&gt;. &lt;B&gt;CardStacks&lt;/B&gt; is a collection of collections, each of which is collection of &lt;B&gt;Cards&lt;/B&gt;. Using &lt;B&gt;ObservableCollection&lt;/B&gt; (which is derived from &lt;B&gt;IList&lt;/B&gt;) 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. &lt;I&gt;All of this requires no UI manipulation code&lt;/I&gt;. &lt;B&gt;GameModel&lt;/B&gt; 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 &lt;B&gt;INotifyPropertyChanged&lt;/B&gt;, which will fire a &lt;B&gt;PropertyChanged&lt;/B&gt; 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? &lt;/P&gt;
&lt;P&gt;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! &lt;/P&gt;
&lt;P&gt;The next step was to get back into Expression Interactive Designer and make this thing look cool. I used a &lt;B&gt;ViewBox&lt;/B&gt; 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. &lt;/P&gt;
&lt;P&gt;A custom &lt;B&gt;Panel&lt;/B&gt; was required for stacking the various cards, so I put my developer hat back on and created CardStackPanel.cs. It exposes an &lt;B&gt;Offset&lt;/B&gt; property that allows the designer to control the &lt;B&gt;Offset&lt;/B&gt; 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: &lt;/P&gt;
&lt;P&gt;&lt;B&gt;Visual C#&lt;/B&gt; &lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; CardStackPanel : StackPanel&lt;BR&gt;{&lt;BR&gt;    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;double&lt;/SPAN&gt; ArrangeOffset&lt;BR&gt;    {&lt;BR&gt;        get { &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; (&lt;SPAN class=kwrd&gt;double&lt;/SPAN&gt;)&lt;SPAN class=kwrd&gt;base&lt;/SPAN&gt;.GetValue(ArrangeOffsetProperty); }&lt;BR&gt;        set { &lt;SPAN class=kwrd&gt;base&lt;/SPAN&gt;.SetValue(ArrangeOffsetProperty, &lt;SPAN class=kwrd&gt;value&lt;/SPAN&gt;); }&lt;BR&gt;    }&lt;BR&gt;&lt;BR&gt;    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;static&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;readonly&lt;/SPAN&gt; DependencyProperty ArrangeOffsetProperty = &lt;BR&gt;        DependencyProperty.Register(&lt;SPAN class=str&gt;"ArrangeOffset"&lt;/SPAN&gt;, &lt;BR&gt;        &lt;SPAN class=kwrd&gt;typeof&lt;/SPAN&gt;(&lt;SPAN class=kwrd&gt;double&lt;/SPAN&gt;), &lt;SPAN class=kwrd&gt;typeof&lt;/SPAN&gt;(CardStackPanel), &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; PropertyMetadata(10.0));&lt;BR&gt;&lt;BR&gt;    &lt;SPAN class=kwrd&gt;protected&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;override&lt;/SPAN&gt; Size ArrangeOverride(Size arrangeSize)&lt;BR&gt;    {&lt;BR&gt;        Rect childArrangeRect = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Rect(arrangeSize);&lt;BR&gt;        childArrangeRect.Y = -1 * &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.ArrangeOffset;&lt;BR&gt;&lt;BR&gt;        &lt;SPAN class=kwrd&gt;for&lt;/SPAN&gt; (&lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; i = 0; i &amp;lt; &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.InternalChildren.Count; i++)&lt;BR&gt;        {&lt;BR&gt;            UIElement child = &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.InternalChildren[i];&lt;BR&gt;            childArrangeRect.Y += &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.ArrangeOffset;&lt;BR&gt;            childArrangeRect.Height = child.DesiredSize.Height;&lt;BR&gt;            child.Arrange(childArrangeRect);&lt;BR&gt;        }&lt;BR&gt;&lt;BR&gt;        &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; arrangeSize;&lt;BR&gt;    }&lt;BR&gt;}&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/STYLE&gt;

&lt;P&gt;&lt;B&gt;Visual Basic&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;&lt;B&gt;&lt;/B&gt;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Class&lt;/SPAN&gt; CardStackPanel &lt;SPAN class=kwrd&gt;Inherits&lt;/SPAN&gt; StackPanel&lt;BR&gt;    &lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Property&lt;/SPAN&gt; ArrangeOffset() &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Double&lt;/SPAN&gt;&lt;BR&gt;        &lt;SPAN class=kwrd&gt;Get&lt;/SPAN&gt;&lt;BR&gt;            &lt;SPAN class=kwrd&gt;Return&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;CDbl&lt;/SPAN&gt;(&lt;SPAN class=kwrd&gt;MyBase&lt;/SPAN&gt;.GetValue(CardStackPanel.ArrangeOffsetProperty))&lt;BR&gt;        &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Get&lt;/SPAN&gt;&lt;BR&gt;        &lt;SPAN class=kwrd&gt;Set&lt;/SPAN&gt;(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; value &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Double&lt;/SPAN&gt;)&lt;BR&gt;            &lt;SPAN class=kwrd&gt;MyBase&lt;/SPAN&gt;.SetValue(CardStackPanel.ArrangeOffsetProperty, value)&lt;BR&gt;        &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Set&lt;/SPAN&gt;&lt;BR&gt;    &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Property&lt;/SPAN&gt;&lt;BR&gt;&lt;BR&gt;    &lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Shared&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;ReadOnly&lt;/SPAN&gt; ArrangeOffsetProperty &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; DependencyProperty&lt;BR&gt;&lt;BR&gt;    &lt;SPAN class=kwrd&gt;Shared&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt;()&lt;BR&gt;        CardStackPanel.ArrangeOffsetProperty = _&lt;BR&gt;            DependencyProperty.Register(&lt;SPAN class=str&gt;"ArrangeOffset"&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;GetType&lt;/SPAN&gt;(&lt;SPAN class=kwrd&gt;Double&lt;/SPAN&gt;), _&lt;BR&gt;            &lt;SPAN class=kwrd&gt;GetType&lt;/SPAN&gt;(CardStackPanel), &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; PropertyMetadata(10.0))&lt;BR&gt;    &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt;&lt;BR&gt;&lt;BR&gt;    &lt;SPAN class=kwrd&gt;Protected&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Overrides&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Function&lt;/SPAN&gt; ArrangeOverride(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; arrangeSize &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Size) _&lt;BR&gt;            &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Size&lt;BR&gt;        &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; childArrangeRect &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; Rect(arrangeSize)&lt;BR&gt;        childArrangeRect.Y = (-1 * &lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.ArrangeOffset)&lt;BR&gt;        &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; childIdx &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Integer&lt;/SPAN&gt; = 0&lt;BR&gt;        &lt;SPAN class=kwrd&gt;Do&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;While&lt;/SPAN&gt; (childIdx &amp;lt; &lt;SPAN class=kwrd&gt;MyBase&lt;/SPAN&gt;.InternalChildren.Count)&lt;BR&gt;            &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; child &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; UIElement = &lt;SPAN class=kwrd&gt;MyBase&lt;/SPAN&gt;.InternalChildren.Item(childIdx)&lt;BR&gt;            childArrangeRect.Y = (childArrangeRect.Y + &lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.ArrangeOffset)&lt;BR&gt;            childArrangeRect.Height = child.DesiredSize.Height&lt;BR&gt;            child.Arrange(childArrangeRect)&lt;BR&gt;            childIdx += 1&lt;BR&gt;        &lt;SPAN class=kwrd&gt;Loop&lt;/SPAN&gt;&lt;BR&gt;        &lt;SPAN class=kwrd&gt;Return&lt;/SPAN&gt; arrangeSize&lt;BR&gt;&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Function&lt;/SPAN&gt;
&lt;/PRE&gt;
&lt;P&gt;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 &lt;B&gt;TextBlock&lt;/B&gt;), select the property you want to bind to (&lt;B&gt;Text &lt;/B&gt;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 &lt;B&gt;StackPanel&lt;/B&gt; that WPF provides (in horizontal mode) and each collection within it was laid out using the custom panel I wrote (and I set the &lt;B&gt;Offset&lt;/B&gt; property to a value that made this look good). &lt;/P&gt;
&lt;P&gt;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. &lt;/P&gt;
&lt;P&gt;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 &lt;B&gt;DataTrigger&lt;/B&gt; 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 &lt;B&gt;Suite&lt;/B&gt; and &lt;B&gt;Card&lt;/B&gt; 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 &lt;B&gt;Brush&lt;/B&gt; set on the control that represents it and thus you have 13 * 4 cards—cool, eh? Unfortunately, you cannot create &lt;B&gt;DataTriggers&lt;/B&gt; 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. &lt;/P&gt;
&lt;P&gt;Here is what the structure of the DataTemplate for a Card looks like:&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;DataTemplate&lt;/SPAN&gt; &lt;SPAN class=attr&gt;x:Key&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="CardTemplate"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Grid&lt;/SPAN&gt; &lt;SPAN class=attr&gt;x:Name&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="Grid1"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Width&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="72"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Height&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="100"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;        &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;ColumnDefinition&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;/&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;        &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;RowDefinition&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;/&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;        &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Control&lt;/SPAN&gt; &lt;SPAN class=attr&gt;x:Name&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="CardDisplayControl"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Margin&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="2,0,2,0"&lt;/SPAN&gt; &lt;BR&gt;            &lt;SPAN class=attr&gt;HorizontalAlignment&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="Stretch"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;VerticalAlignment&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="Stretch"&lt;/SPAN&gt; &lt;BR&gt;            &lt;SPAN class=attr&gt;Width&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="Auto"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Height&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="Auto"&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;/&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;            ....&lt;BR&gt;    &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;Grid&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;DataTemplate.Triggers&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;        &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;DataTrigger&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Binding&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="{Binding Suite}"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;            &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;DataTrigger.Value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;                &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;FreeCell:Suite&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;Hearts&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;FreeCell:Suite&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;            &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;DataTrigger.Value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;            &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Setter&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Property&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="Foreground"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;TargetName&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="CardDisplayControl"&lt;/SPAN&gt;&lt;BR&gt;                &lt;SPAN class=attr&gt;Value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="{StaticResource HeartsDrawingBrush}"&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;/&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;        &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;DataTrigger&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;        ....&lt;BR&gt;        &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;DataTrigger&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Binding&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="{Binding SuiteIndependentCardNumber}"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;            &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;DataTrigger.Value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;                &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;system:Int32&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;1&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;system:Int32&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;            &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;DataTrigger.Value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;            &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;Setter&lt;/SPAN&gt; &lt;SPAN class=attr&gt;Property&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="Template"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;TargetName&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="CardDisplayControl"&lt;/SPAN&gt; &lt;BR&gt;                &lt;SPAN class=attr&gt;Value&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="{StaticResource AceTemplate}"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;/&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;        &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;DataTrigger&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;          ....&lt;BR&gt;    &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;DataTemplate.Triggers&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;DataTemplate&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;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. &lt;/P&gt;
&lt;P&gt;Finally to figure out which card or cell was hit by the user, all one has to do is to add a &lt;B&gt;MouseDown&lt;/B&gt; event. Look at the &lt;B&gt;DataContext&lt;/B&gt; property on the sender of the event. If the &lt;B&gt;DataContext&lt;/B&gt; 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). &lt;/P&gt;
&lt;P&gt;Check it out! It sure is fun!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=912523" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/gaming/default.aspx">gaming</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/card+and+board+games/default.aspx">card and board games</category></item><item><title>Prize Winning Chess Game in C# Express</title><link>http://blogs.msdn.com/coding4fun/archive/2006/01/24/517109.aspx</link><pubDate>Tue, 24 Jan 2006 21:58:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:517109</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/517109.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=517109</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=517109</wfw:comment><description>&lt;P&gt;Kudos to Valentin Iliescu for his &lt;A href="http://codeproject.com/csharp/chess.asp" mce_href="http://codeproject.com/csharp/chess.asp"&gt;Valil.Chess&lt;/A&gt; game on Code Project written with Visual C# 2005 Express Edition.&amp;nbsp;Valentin's work is appreciated by the coding community as evidenced by 1) a 4.85 out of 5.00 rating on Code Project (impressed much), 2) nearly 82,000 views, and 3) the November 2004 Submission Prize at Code Project!&amp;nbsp;Check out this fantastic contribution by one of our Coding4Fun readers by downloading the code yourself.&amp;nbsp;The application is impressive for both it's completeness and features.&amp;nbsp;Way to go, Valentin! [:)]&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=517109" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/gaming/default.aspx">gaming</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/card+and+board+games/default.aspx">card and board games</category></item></channel></rss>