C# 在BackgroundWorker完成之前禁用PictureBoxes和/或更简单的方法

C# 在BackgroundWorker完成之前禁用PictureBoxes和/或更简单的方法,c#,winforms,background,worker,C#,Winforms,Background,Worker,我有一个程序,这是一个游戏,玩家必须匹配两个图像。(图像只是字体和字母)。图像存储在PictureBox中,所有PictureBox都有一个默认图像,单击第一个图像时,将显示下面的图像 此PictureBox保持打开状态,直到玩家单击第二个PictureBox以查看它是否与第一个匹配。如果匹配,两个框都将向玩家显示图像,并且框将被禁用。如果不匹配,两个框都将返回其默认图像 //Code that for when one then two pictures are clicked private

我有一个程序,这是一个游戏,玩家必须匹配两个图像。(图像只是字体和字母)。图像存储在
PictureBox
中,所有
PictureBox
都有一个默认图像,单击第一个图像时,将显示下面的图像

PictureBox
保持打开状态,直到玩家单击第二个
PictureBox
以查看它是否与第一个匹配。如果匹配,两个框都将向玩家显示图像,并且框将被禁用。如果不匹配,两个框都将返回其默认图像

//Code that for when one then two pictures are clicked
private void Picture_Click(object sender, EventArgs e) //Function with two      parameters passed in. 
    {

        Clicked_Picture = (Label)sender; //Sets the Clickd Picture to what ever picture was clicked.

        Number_of_Images++; //Sets number of images to 1.
        if (Number_of_Images < 3) //Should always go into this if statement
        {
            Clicked_Picture.Text = Clicked_Picture.Tag.ToString(); //Setting the text equal to the tag

            if (Number_of_Images == 1) //Go in here if one image is clicked.
            {
                PlaySound.Play();
                Temp_Tag = Clicked_Picture.Tag.ToString(); //Giving the tag string the value of clicked picture tag
                Temp_Pic = Clicked_Picture; //setting the temp pic equal to the cliked picture
                Clicked_Picture.Enabled = false; //Disabling clicked pic so it can't be clicked again so that the user can match

            }
            else if (Number_of_Images == 2) //On second picture click do this...
            {
                if (Temp_Tag != Clicked_Picture.Tag.ToString())
                {
                    PlayNoMatch = new SoundPlayer("NoMatch.wav");
                    PlayNoMatch.Play();
                    tmr_Delay.Enabled = true;
                    Temp_Pic.Enabled = true;//Renabling the picture that was first clicked.                  

                }
                else
                {
                    Clicked_Picture.Enabled = false;
                    if(!bgw_SecondPic.IsBusy)
                    {
                        bgw_SecondPic.RunWorkerAsync();
                    }
                    else
                    {
                        MessageBox.Show("Please Wait");
                    }

                }
                Number_of_Images = 0;//Reset number of images clicked.
            }
        }
    }
但是有一个错误:如果在打开两个不匹配的框时单击第三个框(即快速连续单击三个框),程序将注册该单击并禁用它,而不显示图像,并保持两个不匹配的框打开,直到单击其中一个

下面的图片显示了这一点(忽略头骨和雪花的图片,我在遇到bug之前做了匹配)。这是使用
foreach
循环禁用框的程序

我用尽了所有明显的选项,比如使用
foreach
循环,在进入
if
循环时禁用所有框,在循环中检查它们是否匹配等

当时我在谷歌上看到了后台工作者选项。我尝试了各种方法使用它,但我从来没有得到它的工作方式是假定的。它现在的样子是我对它的最后一个想法

请原谅我,如果它的性能不好,并且远没有达到我想要的效果,但是错误仍然存在……我将
for
循环放入
DoWork
处理程序中,因为您无法访问该处理程序中的UI控件

我在
DoWork
部分中完成了
RunWorkerCompleted
,但由于上述原因,它一直处于冻结状态。这就是使用
BackgroundWorker
选项仍然存在的bug(参见图)。我的印象是,在工作完成之前,表单上的所有内容都被禁用,通过这种逻辑,我不应该单击第三个
PictureBox
,直到其他两个返回默认图像

//Code that for when one then two pictures are clicked
private void Picture_Click(object sender, EventArgs e) //Function with two      parameters passed in. 
    {

        Clicked_Picture = (Label)sender; //Sets the Clickd Picture to what ever picture was clicked.

        Number_of_Images++; //Sets number of images to 1.
        if (Number_of_Images < 3) //Should always go into this if statement
        {
            Clicked_Picture.Text = Clicked_Picture.Tag.ToString(); //Setting the text equal to the tag

            if (Number_of_Images == 1) //Go in here if one image is clicked.
            {
                PlaySound.Play();
                Temp_Tag = Clicked_Picture.Tag.ToString(); //Giving the tag string the value of clicked picture tag
                Temp_Pic = Clicked_Picture; //setting the temp pic equal to the cliked picture
                Clicked_Picture.Enabled = false; //Disabling clicked pic so it can't be clicked again so that the user can match

            }
            else if (Number_of_Images == 2) //On second picture click do this...
            {
                if (Temp_Tag != Clicked_Picture.Tag.ToString())
                {
                    PlayNoMatch = new SoundPlayer("NoMatch.wav");
                    PlayNoMatch.Play();
                    tmr_Delay.Enabled = true;
                    Temp_Pic.Enabled = true;//Renabling the picture that was first clicked.                  

                }
                else
                {
                    Clicked_Picture.Enabled = false;
                    if(!bgw_SecondPic.IsBusy)
                    {
                        bgw_SecondPic.RunWorkerAsync();
                    }
                    else
                    {
                        MessageBox.Show("Please Wait");
                    }

                }
                Number_of_Images = 0;//Reset number of images clicked.
            }
        }
    }

按要求更新原件:

private void Picture_Click(object sender, EventArgs e) //Function with two parameters passed in. 
    {

        Clicked_Picture = (Label)sender; //Sets the Clickd Picture to what ever picture was clicked.

        Number_of_Images++; //Sets number of images to 1.
        if (Number_of_Images < 3) //Should always go into this if statement
        {
            Clicked_Picture.Text = Clicked_Picture.Tag.ToString(); //Setting the text equal to the tag

            if (Number_of_Images == 1) //Go in here if one image is clicked.
            {
                PlaySound.Play();
                Temp_Tag = Clicked_Picture.Tag.ToString(); //Giving the tag string the value of clicked picture tag
                Temp_Pic = Clicked_Picture; //setting the temp pic equal to the cliked picture
                Clicked_Picture.Enabled = false; //Disabling clicked pic so it can't be clicked again so that the user can match

            }
            else if (Number_of_Images == 2) //On second picture click do this...
            {
                if (Temp_Tag != Clicked_Picture.Tag.ToString())
                {
                    PlayNoMatch = new SoundPlayer("NoMatch.wav");
                    PlayNoMatch.Play();
                    tmr_Delay.Enabled = true;
                    Temp_Pic.Enabled = true;//Renabling the picture that was first clicked.                  

                }
                else
                {
                    PlayMatch = new SoundPlayer("match.wav");
                    PlayMatch.Play();
                    Num_Correct++; // counting amount correct
                    lbl_Matches.Text = Num_Correct.ToString();
                    Clicked_Picture.Enabled = false; // disabling picture boxes that are correct match
                    Temp_Pic.Enabled = false;
                    if (Num_Correct == 8) // on game completeion do this..
                    {
                        tmr_counter.Stop();
                        string minutes = Convert.ToString(x);
                        string seconds = Convert.ToString(x + i);
                        if (x < 1)
                        { 
                            MessageBox.Show("Congratulations, all matches complete in " + seconds + " Seconds"); 
                        }
                        else
                        {
                            MessageBox.Show("Congratulations, all matches complete in " + minutes + " Minutes " + seconds + " Seconds "); 
                        }

                        RecordTimeToFile(minutes, seconds,name);

                        this.Close();
                    }
                }
                Number_of_Images = 0;//Reset number of images clicked.
            }
        }
    }
private void Picture\u Click(object sender,EventArgs e)//传入两个参数的函数。
{
Clicked_Picture=(Label)sender;//将单击的图片设置为单击过的图片。
Number_of_Images++;//将图像数设置为1。
if(图像的数量<3)//应始终进入此if语句
{
Clicked_Picture.Text=Clicked_Picture.Tag.ToString();//将文本设置为与标记相等
if(Number_of_Images==1)//如果单击了一个图像,请进入此处。
{
PlaySound.Play();
Temp_Tag=Clicked_Picture.Tag.ToString();//为标记字符串提供单击图片标记的值
Temp_Pic=单击的图片;//将Temp Pic设置为与剪辑的图片相等
Clicked_Picture.Enabled=false;//禁用已单击的pic,以便无法再次单击它,以便用户可以匹配
}
否则,如果(图像的数量==2)//在第二张图片上单击“执行此操作…”。。。
{
if(Temp_Tag!=单击了_Picture.Tag.ToString())
{
PlayNoMatch=新的声音播放器(“NoMatch.wav”);
PlayNoMatch.Play();
tmr_Delay.Enabled=真;
Temp_Pic.Enabled=true;//重新编辑第一次单击的图片。
}
其他的
{
PlayMatch=新的SoundPlayer(“match.wav”);
PlayMatch.Play();
Num_Correct++;//计数金额正确
lbl_Matches.Text=Num_Correct.ToString();
单击了\u Picture.Enabled=false;//禁用正确匹配的图片框
临时图片启用=错误;
如果(Num_Correct==8)//在游戏结束时执行此操作。。
{
tmr_计数器停止();
字符串分钟数=Convert.ToString(x);
字符串秒数=Convert.ToString(x+i);
if(x<1)
{ 
MessageBox.Show(“祝贺您,所有匹配在“+秒+秒”内完成”);
}
其他的
{
MessageBox.Show(“祝贺您,所有比赛在“+分钟+”分钟“+秒+”秒内完成”);
}
RecordTimeToFile(分钟、秒、名称);
这个。关闭();
}
}
图像的数量=0;//重置单击的图像数量。
}
}
}

摆脱那个后台工作人员,把一切都放回原来的Picture\u Click()方法中。现在,在图片的底部单击(),调用
Application.DoEvents()。这将清除该处理程序运行时发生的所有挂起的单击事件,并在方法退出后阻止它们运行:

private void Picture_Click(object sender, EventArgs e) //Function with two      parameters passed in. 
{

    // ... all of your previous code ...

    Application.DoEvents(); // flush the queue before leaving this event
}
请注意,要使其正常工作,需要禁用标签,然后在重新启用它之前调用DoEvents()。下面是一个简单的例子来说明区别:

    private int Number_of_Images;

    private void label1_Click(object sender, EventArgs e)
    {
        label1.Enabled = false;

        Number_of_Images++; 
        label1.Text = "Clicks: " + Number_of_Images.ToString();
        System.Threading.Thread.Sleep(3000);

        label1.Enabled = true;
    }

    private void label2_Click(object sender, EventArgs e)
    {
        label2.Enabled = false;

        Number_of_Images++;
        label2.Text = "Clicks: " + Number_of_Images.ToString();
        System.Threading.Thread.Sleep(3000);
        Application.DoEvents();

        label2.Enabled = true;
    }
单击label1/label2,然后在同一个被禁用时再单击几次以查看差异。

IMHO,没有正确的答案会建议调用
Application.DoEvents()
。很容易将隐藏的重入引入到非为其设计的代码中,导致许多微妙的、难以修复的错误