Displaying imagebuttons on screen

98 Views Asked by At

I am trying to create a chess app in C# using Xamarin.Forms. Right now I am trying to implement the functionality of highlighting and moving pieces. I made code which should display every possible move upon clicking a piece as a clickable image button (clicking those buttons would make the move) however it does not happen and I am really not sure why. This is the code which I think is necessary to understand my problem:

protected virtual void OnPieceClicked(object sender, EventArgs e)
    {
        var pieceButton = (ImageButton)sender;

            //debug
            Console.WriteLine($"_chessboardView is null: {_chessboardView == null}");
            if (_chessboardView != null)
            {
                Console.WriteLine($"_possibleMoveButtons is null: {_chessboardView._possibleMoveButtons == null}");
            }

            Piece clickedPiece = null;
         for (int row = 0; row < 8; row++)
        {
            for (int col = 0; col < 8; col++)
            {
                Piece piece = _chessBoard.Board[row, col];
                if (piece != null && piece.PieceButton == pieceButton)
                {
                    clickedPiece = piece;
                    _currentRow = row;
                    _currentCol = col;
                    break;
                }
            }
            if (clickedPiece != null)
            {
                break;
            }
        }
        
        var possibleMoves = GetPossibleMoves(_currentRow, _currentCol, _chessBoard.Board);

            //debug
            Console.WriteLine($"Number of possible moves for clicked piece: {possibleMoves.Count}");

        foreach (var move in possibleMoves)
        {
            var moveButton = new ImageButton
            {
                Source = "possible_move", // TODO: change pic
                BackgroundColor = Color.Red,
                CommandParameter = move
            };
            moveButton.Clicked += OnMoveClicked;

                _chessboardView._possibleMoveButtons.Add(moveButton);
            _chessboardView._moveButtons.Add(moveButton);
            _chessboardView.Children.Add(moveButton, move.col, move.row);

                //debug
                Console.WriteLine($"Added move button at row {move.row}, col {move.col}");
        }
    }
public void UpdateBoard()
        {
            // Remove previous piece images from the board
            foreach (ImageButton pieceButton in _pieceButtons)
            {
                Children.Remove(pieceButton);
            }
            foreach (ImageButton moveButton in _moveButtons)
            {
                Children.Remove(moveButton);
            }
            foreach (ImageButton possibleMoveButton in _possibleMoveButtons)
            {
                Children.Remove(possibleMoveButton);
            }

            _possibleMoveButtons.Clear();
            _moveButtons.Clear();
            _pieceButtons.Clear();

            //debug
            if (_chessBoard == null)
            {
                System.Diagnostics.Debug.WriteLine("ChessBoard is null");
                return;
            }

            if (_chessBoard.Board == null)
            {
                System.Diagnostics.Debug.WriteLine("ChessBoard's Board is null");
                return;
            }

            for (int row = 0; row < 8; row++)
            {
                for (int col = 0; col < 8; col++)
                {
                    Piece piece = _chessBoard.Board[col, row];
                    if (piece != null)
                    {
                        ImageButton pieceButton = piece.PieceButton;

                        _pieceButtons.Add(pieceButton);
                        Children.Add(pieceButton, col, row);
                    }
                }
            }
        }

I tried placing breakpoints in the code to see if the code even runs and it seems that it runs correctly, it's just the images don't display on the chessboard. I really don't know what to do here. Thank you so much for your help in advance!

EDIT: I'm also adding xaml code and the methods for generating my chessboard if that's helpful:

<StackLayout>
    <local:ChessboardView x:Name="szachownica"
              ChessBoard="{Binding CurrentChessBoard}"
              RowSpacing="0" ColumnSpacing="0"
              Margin="20"
              HeightRequest="{Binding Path=Width, Source={x:Reference szachownica}}"
              InputTransparent="False">
        
    </local:ChessboardView>
    <Button Text="Previous move" Command="{Binding UndoMoveCommand}" />
    <Button Text="New Game" Command="{Binding NewGameCommand}" />
    <Button Text="New Game (vs AI)" Command="{Binding NewGameAICommand}" />
    <Button Text="New Game 960" Command="{Binding NewGame960Command}" />
</StackLayout>
public ChessboardView()
    {
        _possibleMoveButtons = new List<ImageButton>();

        for (int i = 0; i < 8; i++)
        {
            RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
            ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
        }

        for (int row = 0; row < 8; row++)
        {
            for (int col = 0; col < 8; col++)
            {
                BoxView square = new BoxView
                {
                    BackgroundColor = (row + col) % 2 == 0 ? Color.White : Color.Gray
                };

                Children.Add(square, col, row);
            }
        }
    }
    public ChessBoard()
        {
            Board = new Piece[8, 8];
            InitializeBoard();
            
            for (int x = 0; x < 8; x++)
            {
                for (int y = 0; y < 8; y++)
                
                {
                    Piece piece = Board[x, y];
                    if (piece != null)
                    {
                        piece.SetChessBoardAndChessboardView(this, _chessboardView);
                    }
                }
            }
        }
1

There are 1 best solutions below

0
Liqun Shen-MSFT On BEST ANSWER

In your .cs file,

    public MainPage()
    {
        InitializeComponent();
        this.BindingContext = new ChessViewModel();

        var viewModel = new ChessViewModel();
        var chessboardView = new ChessboardView();
        chessBoard = new ChessBoard(chessboardView);
        viewModel.ChessboardView = chessboardView;
        viewModel.CurrentChessBoard = chessBoard;
    }

You define two different ChessViewModel instance. One is for BindingContext. Another is useless. Then you create a new ChessboardView instance. That's not the same as the one (named "szachownica") in xaml. So the imagebutton will not show on "szachownica".

You may change the .cs file like the following:

public partial class MainPage : ContentPage
{
    ChessViewModel viewModel;
    private ChessBoard chessBoard;
    public MainPage()
    {
        InitializeComponent();
        viewModel = new ChessViewModel();
        this.BindingContext = viewModel;

        chessBoard = new ChessBoard(this.szachownica);
        viewModel.ChessboardView = this.szachownica;
        viewModel.CurrentChessBoard = chessBoard;
    }
}

Hope it helps!