An array of two-dimensional int as a PropertyChanged property

Elad Yehuda

Member
Joined
Jul 3, 2023
Messages
9
Programming Experience
3-5
Hello everyone!
I'm writing code in WPF with a UserControl that builds a Sudoku board, so it can be used for any project that wants to add a Sudoku board. The idea I built is that the UserControl receives some kind of main interface that requires implementing special functions for the game itself, for example an interface that requires defining a special function that should actually return a two-dimensional array of int as the structure of a 9X9 Sudoku board given the difficulty level the function will receive. In addition, the interface requires implementing more testing functions in connection with the legality of the game.
which looks like this::
// project UserControl

public interface IGameBoardProvider
{
    int[,] GetBoard(string difficulty);
}

public interface IValidationGameBoardProvider
{
    bool IsBoardValid(int value, int[] indexes);
    int GetMoveValidInBorad(int row_or_col);
       // List<int[]> GetIndexesLocationError(int[] indexes, int value);
}

public interface ICombinedGameBoardProvider : IGameBoardProvider, IValidationGameBoardProvider
{
}

public partial class UserControlBoardGame : UserControl
{
        
     BoardViewModel viewModel;
     public UserControlBoardGame(ICombinedGameBoardProvider boardGame, string level)
     {
         InitializeComponent();
         viewModel = new BoardViewModel(boardGame, level);
         GenerateBoard();
     }
}
// project of WPF in MainWindow
// GameBoardProvider This is a class that inherits the interface ICombinedGameBoardProvider
 public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
           // GameBoardProvider This is a class that inherits the interface
            UserControlBoardGame user = new UserControlBoardGame(new GameBoardProvider(), "Hard");
            GridMain.Children.Add(user);
        }
    }

Now the UserControl itself passes the instance of the interface to the ViewModel class which defines an ObservableCollection of a class I built that inherits directly from TextBox (which will actually contain all the slots on the panel) and in addition holds a property of a two-dimensional array of int that should store the two-dimensional array Dimension received from the function from the interface that returns the array of the game. The UserControl constructor calls a function that dynamically creates the board and in the process calls a special function that is in the ViewModel class to add the appropriate TextBox in the game board.

In addition, there is a special Convter of binding between the -Text property of the text box and the two-dimensional array according to the position, that is, when creating each text box using the row and col indexes, I transfer the indexes to the converter and return the corresponding value according to the requirement.

which looks like this::
[AddINotifyPropertyChangedInterface]
// Model
public class TextBoxCell : TextBox
 { }

// ViewModel
[AddINotifyPropertyChangedInterface]
public class BoardViewModel
{

        public int[,] Board
        {
            get;
            set;
        }

        private ICombinedGameBoardProvider gameBorad;
        public ObservableCollection<TextBoxCell> TextBoxCells { get; set; }
        public BoardViewModel(ICombinedGameBoardProvider gameBorad, string level)
        {
            this.gameBorad = gameBorad;
            TextBoxCells = new ObservableCollection<TextBoxCell>();
            GameNew(level);
        }
        public void GameNew(string level)
        {
           board = this.gameBorad.GetBoard(level);
        }

        public void GenerateTextBoxCell(int[] indexesCell)
        {
            var textBox = new TextBoxCell();
            Func<IValueConverter, Binding> createBinding = (convter) =>
            {
              Binding bind = new Binding("Board")
              {
                     Source = this,
                     Converter = convter,
                     Mode = BindingMode.TwoWay,
                     UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                 };
                return bind;
             };
             textBox.SetBinding(TextBox.TextProperty, createBinding(new CellTextConverter(indexesCell)));
        }

    }

//Converter

public class CellTextConverter : IValueConverter
{

    int row, col;
    public CellTextConverter(int[] indexes)
    {
        this.row = indexes[0];
        this.col = indexes[1];
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
          int[,] arr = (int[,])value;
          string cellValue = arr[row, col].ToString();
          return cellValue != "0" ? cellValue : "";
     }
     //not work well
     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
     {
         return value.ToString() != "" ? int.Parse(value.ToString()) : 0;
     }

}

The code I presented works almost well for me, the only problem with it is that when there is a change in the text box, the converter activates the function ConvertBack - which should return a value according to the two-dimensional array at the index corresponding to that value - the frame of the text box is painted red and rightly so, because the set of the property of the two-dimensional array A dimension expects to receive a value corresponding to a characteristic that is a two-dimensional array and instead it receives a numerical value!
My question is how can I make the property of the two-dimensional array refer when it receives a numerical value to refer to the value to such a value that it should be put according to the appropriate index for it!? I haven't tried but I believe it is possible to return from the converter from the ConvertBack function an object that returns 3 elements the real value and the indexes to put the same value according to the appropriate indexes.
The problem with this is that because I'm actually implementing the set in the property, I'll commit to implementing the get of the property and this is where I get stuck because I can't return a value according to specific indexes!
 
I suggest something that looks like this interface:

C#:
interface IBoard
{
    int Square[int row, int column] { get; set; }
}
 
I suggest something that looks like this interface:

C#:
interface IBoard
{
    int Square[int row, int column] { get; set; }
}

Wow, I didn't know it was possible but I found another way to solve my problem and if you have already offered me a solution, if you could determine for me if it is a correct solution.
My actual solution is instead of defining a property of int [,], I define a variable of type object and a property of the same type and in set I check the value I received of what type it is! As I mentioned in the question, there is the initialization phase and the update phase of the two-dimensional array, then it should receive a two-dimensional array by itself, and I have the phase where I am supposed to update a value in the array, the solution looks like this:

C#:
private object board;

public object Board
{
  get => board;
  set
  {
     if (value is int[,] arr2D)
     {
         board = arr2D;
     }
     else if (value is int[] arrChange)
     {
        (board as int[,])[arrChange[1], arrChange[2]] = arrChange[0];
     }
   }
}
// and in converter
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
    bool isNumber = Regex.IsMatch(value.ToString(), "^[0-9]$");
    if (isNumber)
    {
         int val = value.ToString() == "" ? 0 : int.Parse(value.ToString());
         return new int[] { val, row, col };
     }
         return null;
}
The question is, is this the right way or is it a bit crooked!?
Send the converter the indexes for each text box that is associated with it and through the converter return them back to the property of the class of the collection of text boxes!?

I would love to hear what you think about this!
 
The question is, is this the right way or is it a bit crooked!?

A C#, Java, or C++ programmer would start gathering the townfolk and handing out torches and pitchforks because you basically just threw away compile time type safety. A JavaScript programmer wouldn't blink twice.
 

Latest posts

Back
Top Bottom