将参数传递给事件处理程序

时间:2019-11-02 16:20:59

标签: c# windows-forms-designer

背景: 对于学校作业,我正在做一个益智游戏。玩家必须创建一个益智游戏并将其保存在文本文件中。首先,播放器输入图块(PictureBoxes)的行和列,程序将创建2D PictureBox布局。在哪个播放器选择工具(从ImageList中分配了图像的按钮)并单击图块之后,该图像就会出现在图块上。

方法:我有一个自定义类,该类继承自PictureBox类并具有ToolValue属性。 ToolValue是玩家选择并添加到该PictureBox的工具(为工具分配常数)。为了加载图像,我创建了一个新的事件处理程序,用于处理PictureBox控件的click事件,并在for循环内具有其他参数。新的事件处理程序将图像加载到图块上,并将自定义PictureBox(MyPictureBox)类的ToolValue属性设置为常量。我创建了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属性。如果单击第一个图片框,则传递给事件处理程序的参数对于rowNumber来说是0,对于colNumber是0。事件处理程序参数应该相同,但colNumber参数不为0,而是3,即。生成的2d pictureBoxes的总列。

在此处显示输出>> Colnumber is 3

2 个答案:

答案 0 :(得分:0)

您的问题在以下几行:

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

您正在使用传递rowNumber和colNumber的lambda表达式。 触发图块的Click事件时,将执行lambda,并传递当时的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。

答案 1 :(得分:0)

我可以为您提供大部分一般建议:

首先,WindowsForms和其他GUI技术不是游戏开发的正确工具。它适用于纯粹的回合制,单人或多座位的多人游戏。如果您没有超过图形。基本上,旧的Solitair大约是一切可能的上限。对于认真的开发,您需要使用Game Loop。这是一个学校/学习项目,因此实际上可能会使项目复杂一些。

第二,避免在UI中存储数据。始终在某些集合后面的代码中包含数据(游戏状态)。用户界面只是该数据的表示,您可以定期对其进行更新。

对于传递给事件的参数,这里最有用的应该是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。它需要一个对象,目的似乎是识别仅在此名称/引用不起作用的情况下到达此处的UI元素。诸如图块编号/标识符之类的内容应在此处提供帮助。或数据库行的主键。