Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
158 views
in Technique[技术] by (71.8m points)

C# string array element not updating

I'm learning Blazor to create a web app in C#. One of the pages in the app is the game of Scrabble. Details of my implementation are as following:

  • A Board class storing its size (15 by default) and its premium squares (Double Word, Double Letter, etc...). A Scrabble class implementing UI creation, manipulation, data binding, etc...
  • A new Board instance initializes all square kinds (premium and not)
  • The Scrabble class has an Init method which looks at its Board member for each square's kind then store corresponding color code in a string 2D array (same size as board for easy access). This array later is the problem I'm talking about
  • The UI displays the board using an HTML table with 15 rows, each row with 15 cells whose style attribute is bound with the corresponding color code of the said above string array using Blazor's special syntax @. Each cell also implements an onclick callback, for simplicity I'm only changing the first cell's color (row 0 col 0) to the color of the cell being clicked

The problem:

  • The HTML cell at (0, 0) does not change its color whatsoever. I thought at first that that was due to a binding problem (maybe I used the wrong syntax). So I tried to bind specifically this cell to a seperate string member and it works well. Conclusion: Not a binding problem
  • I add this time some console printings before and after updating the element in the string array to see if the change takes effect, and I found out the problem. The printing shows that the element indeed IS UPDATED CORRECTLY, but as soon as the callback method finishes, the change is reverted and the HTML cell's color stays the same. This is confirmed by clicking again (on any cell because it calls the same callback method), the printing shows that the color code before updating isn't the same as the after of the previous printing, but rather the same as the before. To be specific, the printings are: Click #1: (before) red (after) blue. Click #2: (before) red (after) blue click #2 's before should be blue

The work-around:

  • Tried changing the string array from 2D to 1D, same problem
  • Tried using a List<string>, it works. So I'm sticking to a List for now, but still I prefer array since the 2D index access syntax is neater than using list[15 * row + col] or list[row][col] (nested list)

The question: WHY? Why doens't the array work as intended? Clearly it updated before exiting the method but is reverted afterward

The code:

Board.cs

public class Board
{
    public enum SquareKind
    {
        White,
        DL,
        TL,
        DW,
        TW,
        Start
    }
    public const int SIZE = 15;
    public readonly (int row, int col) StartPos = (7, 7);
    public SquareKind[,] Squares = new SquareKind[SIZE, SIZE];

    public Board()
    {
        // Initialize premium squares (including starting one)
        Squares[0, 0] = SquareKind.TW;
        Squares[1, 5] = SquareKind.TL;
        Squares[5, 1] = SquareKind.TL;
        Squares[5, 5] = SquareKind.TL;
        Squares[1, 1] = SquareKind.DW;
        Squares[2, 2] = SquareKind.DW;
        Squares[3, 3] = SquareKind.DW;
        Squares[4, 4] = SquareKind.DW;
        Squares[0, 3] = SquareKind.DL;
        Squares[3, 0] = SquareKind.DL;
        Squares[2, 6] = SquareKind.DL;
        Squares[6, 2] = SquareKind.DL;
        Squares[6, 6] = SquareKind.DL;
        Squares[0, 14] = SquareKind.TW;
        Squares[1, 9] = SquareKind.TL;
        Squares[5, 13] = SquareKind.TL;
        Squares[5, 9] = SquareKind.TL;
        Squares[1, 13] = SquareKind.DW;
        Squares[2, 12] = SquareKind.DW;
        Squares[3, 11] = SquareKind.DW;
        Squares[4, 10] = SquareKind.DW;
        Squares[0, 11] = SquareKind.DL;
        Squares[3, 14] = SquareKind.DL;
        Squares[2, 8] = SquareKind.DL;
        Squares[6, 12] = SquareKind.DL;
        Squares[6, 8] = SquareKind.DL;
        Squares[14, 14] = SquareKind.TW;
        Squares[13, 9] = SquareKind.TL;
        Squares[9, 13] = SquareKind.TL;
        Squares[9, 9] = SquareKind.TL;
        Squares[13, 13] = SquareKind.DW;
        Squares[12, 12] = SquareKind.DW;
        Squares[11, 11] = SquareKind.DW;
        Squares[10, 10] = SquareKind.DW;
        Squares[14, 11] = SquareKind.DL;
        Squares[11, 14] = SquareKind.DL;
        Squares[12, 8] = SquareKind.DL;
        Squares[8, 12] = SquareKind.DL;
        Squares[8, 8] = SquareKind.DL;
        Squares[14, 0] = SquareKind.TW;
        Squares[13, 5] = SquareKind.TL;
        Squares[9, 1] = SquareKind.TL;
        Squares[9, 5] = SquareKind.TL;
        Squares[13, 1] = SquareKind.DW;
        Squares[12, 2] = SquareKind.DW;
        Squares[11, 3] = SquareKind.DW;
        Squares[10, 4] = SquareKind.DW;
        Squares[14, 3] = SquareKind.DL;
        Squares[11, 0] = SquareKind.DL;
        Squares[12, 6] = SquareKind.DL;
        Squares[8, 2] = SquareKind.DL;
        Squares[8, 6] = SquareKind.DL;
        Squares[7, 0] = SquareKind.TW;
        Squares[0, 7] = SquareKind.TW;
        Squares[14, 7] = SquareKind.TW;
        Squares[7, 14] = SquareKind.TW;
        Squares[3, 7] = SquareKind.DL;
        Squares[7, 3] = SquareKind.DL;
        Squares[7, 11] = SquareKind.DL;
        Squares[11, 7] = SquareKind.DL;
        Squares[StartPos.row, StartPos.col] = SquareKind.Start;
    }
}

Scrabble.razor

@page "/scrabble"
@Init()

<table class="scrabble-board">
    <tbody>
        @for (int i = 0; i < 15; i++)
        {
        <tr>
            @for (int j = 0; j < 15; j++)
            {
                var (row, col) = (i, j);  // Must store i, j here as row, col for callback with parameter using i and j

                <td class="scrabble-board"
                    style="background-color: @squareColors[row, col]"
                    @onclick="@(() => SquareOnClick(row, col))" />
            }
        </tr>
        }
    </tbody>
</table>

Scrabble.razor.cs

public partial class Scrabble
{
    string[,] squareColors = new string[Board.SIZE, Board.SIZE];
    readonly Dictionary<Board.SquareKind, string> colors = new Dictionary<Board.SquareKind, string>
    {
        [Board.SquareKind.White] = "#DDE0DE",
        [Board.SquareKind.DL] = "#87D7F6",
        [Board.SquareKind.TL] = "#25A9DC",
        [Board.SquareKind.DW] = "#F68787",
        [Board.SquareKind.TW] = "#DB1B1B",
        [Board.SquareKind.Start] = "#25DC88"
    };
    Board board = new Board();

    string Init()  // Method returns a null string to be able to run directly on the Blazor page without compiling error
    {
        for (int i = 0; i < Board.SIZE; i++)
            for (int j = 0; j < Board.SIZE; j++)
            {
                var kind = board.Squares[i, j];
                squareColors[i, j] =colors[kind];
            }
        return null;
    }

    void SquareOnClick(int row, int col)
    {
        Console.Write("(before) {0} ", squareColors[0, 0]);
        squareColors[0, 0] = squareColors[row, col];
        Console.WriteLine("(after) {0}", squareColors[0, 0]);
    }
}

For a nicer look, I also used the following CSS (referenced in wwwroot/index.html)

.scrabble-board table {
    width: 100%;
    padding-top: 100%
}

.scrabble-board td {
    border: 1px solid black;
    border-radius: 5px;
    width: 50px;
    height: 50px;
    background-size: contain;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Remove @Init() and initialize by overriding OnInitialized()

using Microsoft.AspNetCore.Components;

public partial class Scrabble : ComponentBase
{

...

    protected override void OnInitialized()
    {
        for (int i = 0; i < Board.SIZE; i++)
            for (int j = 0; j < Board.SIZE; j++)
            {
                var kind = board.Squares[i, j];
                squareColors[i, j] = colors[kind];
            }
    }

...

Every time the render fragment was redrawn you initialized the board. Setting 0,0 to its default red.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...