0

In C# with WPF, how do I draw an Image? I have tried searching online, but all the tutorials I seem to find deal with drawing a shape, or setting a background Image.

I am interested in trying to create a chess program. I have the board set as the background Image, but cannot figure out how to draw images for the pieces.

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Emrys90
  • 1,007
  • 1
  • 10
  • 15
  • You don't "draw" stuff in WPF. you create the proper data and let the UI draw itself. – Federico Berasategui Mar 20 '13 at 00:56
  • I do not see how it is vague. I want to draw the chess pieces on the board. Pawns, knights, etc. I have image files, but do not know how to draw them in the program. – Emrys90 Mar 20 '13 at 00:57

3 Answers3

6

Ok, this is my take on a ChessBoard:

<Window x:Class="MiscSamples.ChessBoard"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MiscSamples"
        Title="ChessBoard" Height="300" Width="300">
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:ChessPiece}">
            <Image Source="{Binding ImageSource}"/>
        </DataTemplate>
    </Window.Resources>

    <Grid>
        <UniformGrid Rows="8" Columns="8" Opacity=".5">
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>

            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>

            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>

            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>

            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>

            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>

            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>

            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>
            <Rectangle Fill="Black"/>
            <Rectangle Fill="White"/>

        </UniformGrid>

        <ItemsControl ItemsSource="{Binding}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid IsItemsHost="True">
                        <Grid.RowDefinitions>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                    </Grid>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Grid.Row" Value="{Binding Row}"/>
                    <Setter Property="Grid.Column" Value="{Binding Column}"/>
                </Style>
            </ItemsControl.ItemContainerStyle>
        </ItemsControl>
    </Grid>
</Window>

Code Behind:

using System.Linq;
using System.Windows;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace MiscSamples
{
    public partial class ChessBoard : Window
    {
        public ObservableCollection<ChessPiece> Pieces { get; set; }

        public ChessBoard()
        {
            Pieces = new ObservableCollection<ChessPiece>();
            InitializeComponent();
            DataContext = Pieces;
            NewGame();
        }

        private void NewGame()
        {
            Pieces.Clear();
            Pieces.Add(new ChessPiece() { Row = 0, Column = 0, Type = ChessPieceTypes.Tower, IsBlack = true});
            Pieces.Add(new ChessPiece() { Row = 0, Column = 1, Type = ChessPieceTypes.Knight, IsBlack = true });
            Pieces.Add(new ChessPiece() { Row = 0, Column = 2, Type = ChessPieceTypes.Bishop, IsBlack = true });
            Pieces.Add(new ChessPiece() { Row = 0, Column = 3, Type = ChessPieceTypes.Queen, IsBlack = true });
            Pieces.Add(new ChessPiece() { Row = 0, Column = 4, Type = ChessPieceTypes.King, IsBlack = true });
            Pieces.Add(new ChessPiece() { Row = 0, Column = 5, Type = ChessPieceTypes.Bishop, IsBlack = true });
            Pieces.Add(new ChessPiece() { Row = 0, Column = 6, Type = ChessPieceTypes.Knight, IsBlack = true });
            Pieces.Add(new ChessPiece() { Row = 0, Column = 7, Type = ChessPieceTypes.Tower, IsBlack = true });

            Enumerable.Range(0, 8).Select(x => new ChessPiece()
                {
                    Row = 1, 
                    Column = x, 
                    IsBlack = true, 
                    Type = ChessPieceTypes.Pawn
                }).ToList().ForEach(Pieces.Add);


            Pieces.Add(new ChessPiece() { Row = 7, Column = 0, Type = ChessPieceTypes.Tower, IsBlack = false });
            Pieces.Add(new ChessPiece() { Row = 7, Column = 1, Type = ChessPieceTypes.Knight, IsBlack = false });
            Pieces.Add(new ChessPiece() { Row = 7, Column = 2, Type = ChessPieceTypes.Bishop, IsBlack = false });
            Pieces.Add(new ChessPiece() { Row = 7, Column = 3, Type = ChessPieceTypes.Queen, IsBlack = false });
            Pieces.Add(new ChessPiece() { Row = 7, Column = 4, Type = ChessPieceTypes.King, IsBlack = false });
            Pieces.Add(new ChessPiece() { Row = 7, Column = 5, Type = ChessPieceTypes.Bishop, IsBlack = false });
            Pieces.Add(new ChessPiece() { Row = 7, Column = 6, Type = ChessPieceTypes.Knight, IsBlack = false });
            Pieces.Add(new ChessPiece() { Row = 7, Column = 7, Type = ChessPieceTypes.Tower, IsBlack = false });

            Enumerable.Range(0, 8).Select(x => new ChessPiece()
            {
                Row = 6,
                Column = x,
                IsBlack = false,
                Type = ChessPieceTypes.Pawn
            }).ToList().ForEach(Pieces.Add);

        }
    }

ViewModel:

    public class ChessPiece: INotifyPropertyChanged
    {
        public bool IsBlack { get; set; }

        public ChessPieceTypes Type { get; set; }


        private int _row;
        public int Row
        {
            get { return _row; }
            set
            {
                _row = value;
                OnPropertyChanged("Row");
            }
        }

        private int _column;
        public int Column
        {
            get { return _column; }
            set
            {
                _column = value;
                OnPropertyChanged("Column");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }

        public string ImageSource 
        {
            get { return "../ChessPieces/" + (IsBlack ? "Black" : "White") + Type.ToString() + ".png"; }
        }
    }

    public enum ChessPieceTypes
    {
        Pawn,
        Tower,
        Knight,
        Bishop,
        Queen,
        King,
    }
}

This is what it looks like in my computer:

enter image description here

Please notice that I'm using pure XAML to create the UI. In no way Im creating nor manipulating UI elements in code. WPF doesn't need that, and it's also not recommended.

The recommended approach to WPF is to use MVVM and understand that UI is Not Data

You can copy and paste my code in a File -> New Project -> WPF Application and see the results for yourself. You will need the following project structure:

enter image description here

Also note that the Image files need to be set to Build Action: Resource.

Remember: This is the WPF approach to EVERYTHING. You rarely have to manipulate UI elements in code in WPF, or do things such as drawing or anything like that.

Community
  • 1
  • 1
Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
0

For bitmaps, you can use BitmapImage:

http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapimage.aspx

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Keith Nicholas
  • 43,549
  • 15
  • 93
  • 156
  • Sorry for my ignorance, but can you give an example? I am new to GUI development. I do not know exactly what to do. I have a canvas with a background image, but do not know where to go from there. – Emrys90 Mar 20 '13 at 00:59
0

It depends on how you whould like to draw i usually work with bit drawing and here is the way i do it.

//Initialize image and stuff
int Width = 100;
int Height = 100;
int nStride = (Width * PixelFormats.Bgra32.BitsPerPixel + 7) / 8;
Int32Rect ImageDimentions = new Int32Rect(0, 0, Width, Height);
int[] ImageArr = new ImageArr[Height * nStride];

//Manually paint your image
for (int Y = 0; Y < Height; Y++)
{
    for (int X = 0; X < Width; X++)
    {
       //X and Y means pixel(X,Y) in cartesian plane 1 quadrant mirrored around X axis
       //Down is the Y from 0 to height, and right to left is X from 0 to width
       int index = (Y * Width + X) * 4;
       ImageArr[index + 0] = (byte)0;   //Blue
       ImageArr[index + 1] = (byte)0;   //Green
       ImageArr[index + 2] = (byte)0;   //Red
       ImageArr[index + 3] = (byte)255; //Alpha
    }
}

//Push your data to a Bitmap
WriteableBitmap BmpToWriteOn = new WriteableBitmap(Width, Height, 96, 96, PixelFormats.Bgra32, null);
BmpToWriteOn.WritePixels(ImageDimentions, ImageArr, nStride, 0, 0);     

//Push your bitmap to Xaml Image
YourXamlImage.Source = BmpToWriteOn;
Thomas Andreè Wang
  • 3,379
  • 6
  • 37
  • 53
  • WHAT?? What do you want that for? – Federico Berasategui Mar 20 '13 at 02:47
  • I use it to run simulations where i have output best viewed visually, an example is what I'm working on atm, I'm going to simulate an AI moving through an environment with a camera building a map of the environment it traverses, and then to build the light shader i need methods like this, albeit not as simple as it as i use multiple hacks to update as few pixels as possible (Only those who changes). – Thomas Andreè Wang Mar 20 '13 at 17:28
  • and what does all that have to do with a ChessBoard? – Federico Berasategui Mar 20 '13 at 17:30
  • He wanted a way to draw and it and i just gave a extra way to do it. He could load the board and pieces as individual images convert them to int arrays, then to write them on the board in the position needed creating a chessboard, the difference with your approach and this one is that with this one you have to be careful but you have total control. – Thomas Andreè Wang Mar 20 '13 at 17:41
  • `but you have total control` - You also have total control doing the UI the right way in XAML instead of code. Your approach makes no sense for such a simple task. – Federico Berasategui Mar 20 '13 at 17:51
  • its just a different approach – Thomas Andreè Wang Mar 20 '13 at 18:02