Передача параметров в обработчик событий - PullRequest
0 голосов
/ 02 ноября 2019

Фон: Для школьного задания я делаю игру-головоломку. Игрок должен создать игру-головоломку и сохранить ее в текстовом файле. Сначала игрок вводит строки и столбцы тайлов (PictureBoxes), программа создает 2d макет PictureBox. После чего игрок выбирает инструмент (кнопка, назначенная изображение из ImageList) и нажимает на плитку, изображение появляется на плитке.

Подход: у меня есть собственный класс, который наследуется от класса PictureBox и имеет свойство ToolValue. ToolValue - это инструмент (постоянная, назначаемая инструменту), выбранный игроком и добавленный в этот PictureBox. Для загрузки изображения я создал новый обработчик событий, который обрабатывает событие click элемента управления PictureBox и имеет дополнительные параметры внутри цикла for. Новый обработчик событий загружает изображение на плитку и устанавливает постоянное значение свойства ToolValue пользовательского класса PictureBox (MyPictureBox). Я создал двумерный массив ссылок на класс PictureBox.

MyPictureBox[,] Tile;

        public void DrawALineOfPictureBoxes(int rowNumber, int columnCount, int rowCount, int leftPosition, int topPosition, int height, int width)
        {
            Tile = new MyPictureBox[rowCount, columnCount];
            for (int colNumber = 0; colNumber < columnCount; colNumber++)
            {
                Tile[rowNumber, colNumber] = new MyPictureBox();
                Tile[rowNumber, colNumber].Left = leftPosition;
                Tile[rowNumber, colNumber].Top = topPosition;
                Tile[rowNumber, colNumber].Height = height;
                Tile[rowNumber, colNumber].Width = width;
                Tile[rowNumber, colNumber].BorderStyle = BorderStyle.Fixed3D;
                Tile[rowNumber, colNumber].SizeMode = PictureBoxSizeMode.StretchImage;
                Tile[rowNumber, colNumber].ToolValue = 0;
                Tile[rowNumber, colNumber].Click += new EventHandler((sender,e) => LoadImage_Click(sender, e, rowNumber, colNumber));
                this.Controls.Add(Tile[rowNumber, colNumber]);

                leftPosition += width;
            }
        }
        /// <summary>
        /// Method executes when Generate Button is clicked  
        /// Method invokes DrawALineOfPictureBoxes method which generates a row of Picture boxes
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// 
        private void PictureBoxGenerate_Click(object sender, EventArgs e)
        {
            try
            {
                int numRows = int.Parse(txtRowCount.Text);
                int numColumns = int.Parse(txtColumnCount.Text);
                int leftPos = 400;
                int topPos = 120;
                int height = 100;
                int width = 100;
                //loop after each row of picturebox is generated
                for (int rowNumber = 0; rowNumber < numRows; ++rowNumber)
                {
                    DrawALineOfPictureBoxes(rowNumber, numColumns, numRows, leftPos, topPos, height, width);
                    topPos += height;
                }
            }
            catch (FormatException)
            {
                MessageBox.Show("Please provide valid data for rows and columns (Both must be integers)","Sokoban", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }


        /// <summary>
        /// Method is executed when PictureBox cell is clicked and load image to that picture box through resources
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LoadImage_Click(object sender, EventArgs e, int rowNumber, int colNumber)
        {
            string Content = rowNumber.ToString() + "," + colNumber.ToString();
            Console.WriteLine(Content);
            MyPictureBox pictureBox = sender as MyPictureBox;
            switch (imageType)
            {
                case ImageType.None:
                    //Empty the pictureBox Cell
                    pictureBox.Image = null;
                    ToolVal = 0;

                    break;
                case ImageType.Hero:
                    pictureBox.Image = Properties.Resources.Hero;
                    ToolVal = 1;
                    break;
                case ImageType.Wall:
                    pictureBox.Image = Properties.Resources.Wall;
                    ToolVal = 2;
                    break;
                case ImageType.Box:
                    pictureBox.Image = Properties.Resources.Box;
                    ToolVal = 3;
                    break;
                case ImageType.Destination:
                    pictureBox.Image = Properties.Resources.Destination;
                    ToolVal = 4;
                    break;
                default:
                    break;
            }
            //assigning values to Tile array
            Tile[rowNumber,colNumber].ToolValue = ToolVal;
        }

Проблема: я передал номер строки и столбца pictureBox, который щелкается в качестве параметра для EventHandler, который загружает изображение. Внутри обработчика событий цикл переключения проверяет, какой инструмент был выбран, и соответственно присваивает константу свойству toolValue. Если я нажимаю на первое поле рисунка, параметры, передаваемые обработчику событий, равны 0 для rowNumber и 0 для colNumber. Параметры обработчика событий должны быть одинаковыми, но аргумент colNumber не равен 0, а равен 3, т.е. общее количество столбцов сгенерированных 2d pictureBox.

Вот результат >> >> 1008 * Число равно 3

Ответы [ 2 ]

0 голосов
/ 02 ноября 2019

Я могу дать вам в основном общие советы:

Прежде всего, WindowsForms и другие технологии GUI не являются подходящим инструментом для разработки игр. Он работает для многопользовательских игр с простым ходом, одиночной или горячей игры. Если вы не над графикой. В основном старый Solitair был о верхнем конце того, что возможно. Для серьезного развития вам нужно что-то с Game Loop. Это школьный / учебный проект, поэтому он может быть немного сложным для проекта.

Во-вторых, избегайте хранения данных в пользовательском интерфейсе. Всегда храните данные (состояние игры) в коде в некоторой коллекции. Интерфейс пользователя - это просто представление этих данных, которые вы регулярно обновляете.

Что касается аргументов, передаваемых в События, то наиболее полезным здесь должен быть sender. Это тот случай, который вызвал событие. Вы можете проверить это следующим образом:

//Shared handler for OK, Apply and Cancel Buttons
if(sender == btnOK || sender == btnApply){

}
if(sender == btnOK || sender == btnCancel){

}

Или вы можете разыграть его, чтобы получить полный доступ к свойствам отправителей

PictureBox source = (PictureBox)sender;
source.ImageLocataion = "clicked.png";

Одно конкретное свойство примечания - Tag . Это берет объект, и его цель, кажется, состоит в том, чтобы идентифицировать, какой элемент пользовательского интерфейса вы получили здесь, если только имя / ссылка не работает. Здесь должно помочь что-то вроде номера плитки / Идентификатора. Или первичный ключ строки базы данных.

0 голосов
/ 02 ноября 2019

Ваша проблема в следующей строке:

Tile[rowNumber, colNumber].Click += new EventHandler((sender,e) => LoadImage_Click(sender, e, rowNumber, colNumber));

Вы используете лямбда-выражение, которое передает rowNumber & colNumber. Когда событие Click для плитки запускается, лямбда-функция выполняется и передает значения rowNumber и colNumber, которые имели в то время (а не значения, которые они имели при создании обработчика события). Поскольку ваш цикл завершен, значение colNumber, которое вы передаете, всегда будет 3.

Так что вам нужен другой механизм для вычисления строки и столбца для выбранной плитки. Вы можете сделать это на основе переданного отправителя: привести его к Tile, получить его положение и вычислить строку и столбец из этого.

Если вы действительно хотите передать фактическое число столбцов, вы всегда можете'захватить значение для' colNumber 'следующим образом:

Tile = new MyPictureBox[rowCount, columnCount];
        for (int colNumber = 0; colNumber < columnCount; colNumber++)
        {
            int actualColumn = colNumber;
            int actualRow = rowNumber; 

            Tile[rowNumber, colNumber] = new MyPictureBox();
            ...
            Tile[rowNumber, colNumber].Click += new EventHandler((sender,e) => LoadImage_Click(sender, e, actualRow, actualColumn));
            this.Controls.Add(Tile[rowNumber, colNumber]);

            leftPosition += width;
        }

Для каждой итерации цикла, в котором вы создаете свои плитки, вы создаете новую переменную, которая содержит фактические строку и столбец для вашей плитки. Эти значения не изменятся, потому что каждая итерация имеет свою собственную версию. И вы передаете эти переменные вместо rowNumber и colNumber.

...