WPF controls needed to build chess application

I am trying to build a chess application. I have the backend logic in place (almost). But I havent worked much on UIs. I plan to use C# and I hear WPF is the way to go.

Could you please give me pointers as to how to build the UI interface and the various coins over it? Will I have to build some kind of controls for the coins? Also, what control should I use to develop the board?


Solution 1:

I'm gonna have another shot at this question and actually show you how to do this properly with WPF. Be warned though, if you've never done any WPF before then this might be a bit overwhelming at first, but hopefully it should give some idea of just how data-driven WPF is and how powerful it can be once you get the hang of it.

First you'll need to create a WPF project and run NuGet package manager to add the MVVM Light package (or add it manually if you prefer). Next you'll want to set up a couple of enums to define your piece type and a class to represent an actual instance of a piece on the board:

public enum PieceType
{
    Pawn,
    Rook,
    Knight,
    Bishop,
    Queen,
    King
}

public enum Player
{
    White,
    Black
}

public class ChessPiece : ViewModelBase
{
    private Point _Pos;
    public Point Pos
    {
        get { return this._Pos; }
        set { this._Pos = value; RaisePropertyChanged(() => this.Pos); }
    }

    private PieceType _Type;
    public PieceType Type
    {
        get { return this._Type; }
        set { this._Type = value; RaisePropertyChanged(() => this.Type); }
    }

    private Player _Player;
    public Player Player
    {
        get { return this._Player; }
        set { this._Player = value; RaisePropertyChanged(() => this.Player); }
    }
}

Almost everything else from here on is done in XAML. First you need to create a checkerboard brush for the board itself, this can be a bitmap if you like but I'll go ahead and create a geometry drawing instead. This code needs to be placed in your Window.Resources section:

<DrawingBrush x:Key="Checkerboard" Stretch="None" TileMode="Tile" Viewport="0,0,2,2" ViewportUnits="Absolute">
        <DrawingBrush.Drawing>
            <DrawingGroup>
                <GeometryDrawing Brush="Tan">
                    <GeometryDrawing.Geometry>
                        <RectangleGeometry Rect="0,0,2,2" />
                    </GeometryDrawing.Geometry>
                </GeometryDrawing>
                <GeometryDrawing Brush="Brown">
                    <GeometryDrawing.Geometry>
                        <GeometryGroup>
                            <RectangleGeometry Rect="0,0,1,1" />
                            <RectangleGeometry Rect="1,1,1,1" />
                        </GeometryGroup>
                    </GeometryDrawing.Geometry>
                </GeometryDrawing>
            </DrawingGroup>
        </DrawingBrush.Drawing>
    </DrawingBrush>

Next up you'll need a way to select an image based on the piece you're rendering. There are many ways to do this but the way I'm going to do it here is to declare an Image style and then use triggers that select the appropriate bitmap based on the piece type and player. For this example I'll just hot-link to some clip-art on the wpclipart site. This block of XAML is long but it's just doing the same thing for each piece type:

<Style x:Key="ChessPieceStyle" TargetType="{x:Type Image}">
        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Pawn}"/>
                    <Condition Binding="{Binding Player}" Value="{x:Static local:Player.White}"/>
                </MultiDataTrigger.Conditions>  
                <MultiDataTrigger.Setters>
                    <Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_white_pawn_T.png" />
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Rook}"/>
                    <Condition Binding="{Binding Player}" Value="{x:Static local:Player.White}"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_white_rook_T.png" />
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Knight}"/>
                    <Condition Binding="{Binding Player}" Value="{x:Static local:Player.White}"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_white_knight_T.png" />
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Bishop}"/>
                    <Condition Binding="{Binding Player}" Value="{x:Static local:Player.White}"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_white_bishop_T.png" />
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Queen}"/>
                    <Condition Binding="{Binding Player}" Value="{x:Static local:Player.White}"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_white_queen_T.png" />
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.King}"/>
                    <Condition Binding="{Binding Player}" Value="{x:Static local:Player.White}"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_white_king_T.png" />
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Pawn}"/>
                    <Condition Binding="{Binding Player}" Value="{x:Static local:Player.Black}"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_black_pawn_T.png" />
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Rook}"/>
                    <Condition Binding="{Binding Player}" Value="{x:Static local:Player.Black}"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_black_rook_T.png" />
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Knight}"/>
                    <Condition Binding="{Binding Player}" Value="{x:Static local:Player.Black}"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_black_knight_T.png" />
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Bishop}"/>
                    <Condition Binding="{Binding Player}" Value="{x:Static local:Player.Black}"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_black_bishop_T.png" />
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.Queen}"/>
                    <Condition Binding="{Binding Player}" Value="{x:Static local:Player.Black}"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_black_queen_T.png" />
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Type}" Value="{x:Static local:PieceType.King}"/>
                    <Condition Binding="{Binding Player}" Value="{x:Static local:Player.Black}"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="Image.Source" Value="http://www.wpclipart.com/recreation/games/chess/chess_set_1/chess_piece_black_king_T.png" />
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>

And now the board itself. With the above code set up this bit is surprisingly short, we're just going to render an ItemsControl (i.e. a list of items), we'll set the container to be a canvas, we'll set it's background to our checkerboard and for each piece we'll set the position based on the Pos property. Obviously we'll also use the ChessPieceStyle Image style that we set up above to select the correct image to render:

<ItemsControl Name="ChessBoard">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Width="8" Height="8" Background="{StaticResource Checkerboard}"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid Width="1" Height="1">
                    <Image Width="0.8" Height="0.8" Style="{StaticResource ChessPieceStyle}" />                     
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Canvas.Left" Value="{Binding Pos.X}" />
                <Setter Property="Canvas.Top" Value="{Binding Pos.Y}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>

And that's it! We now have everything we need to render a chess board. All that remains is to create an array of our pieces, put it in an ObservableCollection (so that the GUI gets updates when pieces added and removed) and bind it to our chessboard:

this.ChessBoard.ItemsSource = new ObservableCollection<ChessPiece>
        {
            new ChessPiece{Pos=new Point(0, 6), Type=PieceType.Pawn, Player=Player.White},
            new ChessPiece{Pos=new Point(1, 6), Type=PieceType.Pawn, Player=Player.White},
            new ChessPiece{Pos=new Point(2, 6), Type=PieceType.Pawn, Player=Player.White},
            new ChessPiece{Pos=new Point(3, 6), Type=PieceType.Pawn, Player=Player.White},
            new ChessPiece{Pos=new Point(4, 6), Type=PieceType.Pawn, Player=Player.White},
            new ChessPiece{Pos=new Point(5, 6), Type=PieceType.Pawn, Player=Player.White},
            new ChessPiece{Pos=new Point(6, 6), Type=PieceType.Pawn, Player=Player.White},
            new ChessPiece{Pos=new Point(7, 6), Type=PieceType.Pawn, Player=Player.White},
            new ChessPiece{Pos=new Point(0, 7), Type=PieceType.Rook, Player=Player.White},
            new ChessPiece{Pos=new Point(1, 7), Type=PieceType.Knight, Player=Player.White},
            new ChessPiece{Pos=new Point(2, 7), Type=PieceType.Bishop, Player=Player.White},
            new ChessPiece{Pos=new Point(3, 7), Type=PieceType.King, Player=Player.White},
            new ChessPiece{Pos=new Point(4, 7), Type=PieceType.Queen, Player=Player.White},
            new ChessPiece{Pos=new Point(5, 7), Type=PieceType.Bishop, Player=Player.White},
            new ChessPiece{Pos=new Point(6, 7), Type=PieceType.Knight, Player=Player.White},
            new ChessPiece{Pos=new Point(7, 7), Type=PieceType.Rook, Player=Player.White},
            new ChessPiece{Pos=new Point(0, 1), Type=PieceType.Pawn, Player=Player.Black},
            new ChessPiece{Pos=new Point(1, 1), Type=PieceType.Pawn, Player=Player.Black},
            new ChessPiece{Pos=new Point(2, 1), Type=PieceType.Pawn, Player=Player.Black},
            new ChessPiece{Pos=new Point(3, 1), Type=PieceType.Pawn, Player=Player.Black},
            new ChessPiece{Pos=new Point(4, 1), Type=PieceType.Pawn, Player=Player.Black},
            new ChessPiece{Pos=new Point(5, 1), Type=PieceType.Pawn, Player=Player.Black},
            new ChessPiece{Pos=new Point(6, 1), Type=PieceType.Pawn, Player=Player.Black},
            new ChessPiece{Pos=new Point(7, 1), Type=PieceType.Pawn, Player=Player.Black},
            new ChessPiece{Pos=new Point(0, 0), Type=PieceType.Rook, Player=Player.Black},
            new ChessPiece{Pos=new Point(1, 0), Type=PieceType.Knight, Player=Player.Black},
            new ChessPiece{Pos=new Point(2, 0), Type=PieceType.Bishop, Player=Player.Black},
            new ChessPiece{Pos=new Point(3, 0), Type=PieceType.King, Player=Player.Black},
            new ChessPiece{Pos=new Point(4, 0), Type=PieceType.Queen, Player=Player.Black},
            new ChessPiece{Pos=new Point(5, 0), Type=PieceType.Bishop, Player=Player.Black},
            new ChessPiece{Pos=new Point(6, 0), Type=PieceType.Knight, Player=Player.Black},
            new ChessPiece{Pos=new Point(7, 0), Type=PieceType.Rook, Player=Player.Black}
        };

And here's the result:

WPF chessboard

That might seem like a lot of work just to draw a chessboard but keep in mind that this is now a completely data-driven interface....if you add or remove pieces or change any of the fields in the piece in your piece array then those changes will propagate through to the front-end immediately. It's also very easy to expand, modify and add additional features such as animation, 3D, reflections etc. But perhaps the most impressive thing is that I didn't have to create any custom user controls at all in order to do this, the WPF data binding mechanism is powerful enough to support this kind of stuff out-of-the-box easily.

If you need any further clarifications and/or would like to see a standalone project then by all means let me know.

Solution 2:

If it's 2D then Canvas is the obvious way to go, you can place Images on it or anything else you like and move them to arbitrary positions. You can also wrap it up in a Viewbox so that it, and everything in it, scales automatically to the parent window.

In general you shouldn't need to make any user controls. WPF places much less emphasis on user controls, in general you only need them when you need to add very specific behavior not covered by the existing framework that needs to be duplicated. That's unlikely to be the case in a chess application.

Solution 3:

ComponentOne has a a Silverlight demo of this board game called checkers. You can view this demo online and the source code is available for free. Definitely, it can be a lot helpful for you to get started. Note that porting to WPF would be rather easy.

Solution 4:

1. Design the canvas and decide how much size you will give to the board or how much to the scoring area or players name or any other additional information you want to show during the game.

2. Design coin's images, and board background image

3. Now set up the scene, you should have an individual class for graphics. It would be easier to update it and handle it (Its up to you that how you write it).

4. Create a class for animation, that how an image will move on a particular action.

5. Create an individual class for sounds if you plan to use.

6. Create another class containing the game logic

7. One more class you will need for the player

After doing them, its all up to your logic that how you handle them all.

A link is here, its on vb.net but you can get an idea of designing the UI.