Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/256.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# winform问题的多线程和图像绘制_C#_Winforms_Multithreading_Drawing - Fatal编程技术网

C# winform问题的多线程和图像绘制

C# winform问题的多线程和图像绘制,c#,winforms,multithreading,drawing,C#,Winforms,Multithreading,Drawing,我正在构建一个国际象棋游戏,我有一个循环,它穿过一系列对象并在winforms上绘制棋子的图像(每个图片框代表一个棋子) 每次按下“重播”按钮都会触发该功能 在上面的这个方法中,我得到一个竞态条件和两个线程相互碰撞..(同时进入循环) 在我第二次按“重播”按钮后,错误随机发生。。(这表示运行条件/多个线程进入循环) 我读了更多关于异常的内容…: System.InvalidOperationException:对象当前正在使用 其他地方 GDI+正在抱怨设备上下文(DC)正在尝试 使用已在“使用

我正在构建一个国际象棋游戏,我有一个循环,它穿过一系列对象并在winforms上绘制棋子的图像(每个图片框代表一个棋子)

每次按下“重播”按钮都会触发该功能

在上面的这个方法中,我得到一个竞态条件和两个线程相互碰撞..(同时进入循环)

在我第二次按“重播”按钮后,错误随机发生。。(这表示运行条件/多个线程进入循环)

我读了更多关于异常的内容…:

System.InvalidOperationException:对象当前正在使用 其他地方

GDI+正在抱怨设备上下文(DC)正在尝试 使用已在“使用中”。对于winforms,这通常意味着 recursive Graphics.GetHdc必须在任何其他之前匹配ReleaseHdc GetHdc

如果从多个线程绘制到表单,则会发生此错误。 交叉线程异常也可能发生

潜在的解决方案是在访问表单时不使用多个线程,包括线程

InvalidOperationException用于调用失败的情况 方法是由无效参数以外的原因引起的。对于 例如,InvalidOperationException由以下人员引发:

如果在枚举数之后修改集合的对象,则移动下一步 是创建的

我认为doWork事件处理程序方法中的循环需要保护…我需要在另一个RunAsync启动之前终止RunAsync..这被证明是不成功的

任何解决方案都会有所帮助


注意:提供比我在这里提供的更多的代码不会添加任何内容。我花了一整天的时间来处理那个被窃听的问题。我知道

在调用RunWorkerAsync时禁用该按钮,并在完成处理程序和CalcInstallation中重新启用它

在循环结束时,让DoWork方法完成—您不需要尝试取消它

但是,我怀疑问题在于您正在从工作线程操作UI(工作线程正在调用打印件)。你不知道;我没有向我们展示这个片段的print方法中的代码是什么样子的,但我怀疑它没有进行线程编组

创建SynchronizationContext类型的成员变量(称为say uiCtx),并在窗体加载事件中初始化它,如下所示

uiCtx = SynchronizationContext.Current;
现在,在Dowork方法中,将其更改为以下内容

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    //replay is an array of the chess moves that were made since the start of the game.

    foreach (KeyValuePair<int, int[]> item in replay)// count should be more than 2
    {
         if (!backgroundWorker1.CancellationPending)
         {
              // ...
              uiCtx.Post(o =>
              {
                  PrintPieces(codeFile.PieceState());
              ), null);

              System.Threading.Thread.Sleep(1000);
         }
         else
         {
              break;
         }

     }

 }
private void backgroundWorker1\u DoWork(对象发送方,DoWorkEventArgs e)
{
//重播是自游戏开始以来进行的一系列国际象棋动作。
foreach(replay中的KeyValuePair项)//计数应大于2
{
如果(!backgroundWorker1.CancellationPending)
{
// ...
uiCtx.Post(o=>
{
打印件(codeFile.PieceState());
),空);
系统线程线程睡眠(1000);
}
其他的
{
打破
}
}
}
Post方法使lambda表达式在UI线程上运行

更新,对此处发生的情况进行更多解释

在Windows中,你不能从创建UI的线程以外的线程访问UI,换句话说,你不能从后台线程访问UI。我认为发生的事情是在实际绘制的UI中,你正在操纵设备上下文来绘制UI,主线程也在做同样的事情,所以你得到了你的例外

SynchronizationContext是一个独立于框架的抽象,可用于使功能在“正确”线程上运行。WinForms、WPF、Silverlight和ASP.NET都有一个实现。WinForms one只是Control.BeginImvoke等的包装器


SynchronizationContext.Post接受一个lambda表达式,并获取该lambda以在WinForms情况下的UI线程上执行。这意味着您对设备上下文的所有操作现在都发生在UI线程上,因此您将不会让两个线程同时访问它(因此您的异常消失)

我确实展示了打印方法中该方法的外观..看上面这是第一种方法..它打印棋子数组(所有棋子对象的数组..每个棋子在二维piecs数组中都有一个位置..例如Kingschesspiece对象是棋子[8,4]..现在我将测试您的代码..我还认为线程的运行速度比winform自身绘制的速度更快、更慢…缺少同步我的意思是您没有显示进行打印的实际代码:chessPics[I,j].Load(片段[I,j].print());画板会很快,你想从UI线程中得到的是睡眠。编辑答案中的更多细节谢谢,winforms和线程听起来很复杂,我最好还是使用asp.net。我已经完成了winform编程
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {

              //replay is an array of the chess moves that were made since
the start of the game.
                        foreach (KeyValuePair<int, int[]> item in replay)// count should be more than 2
                        {
                            if (!backgroundWorker1.CancellationPending)
                            {
                                //There is more code here that wasnt presented 
                                //It basically executes each move from the replay
                                //array and return the chess pieces array (the positions
                                //of the current game after each move from teh replay array
                                //was executed)..The current game state returns in a form 
                                //of an array and returns from the method:                 
                                PrintPieces(codeFile.PieceState());
                            }
                            else
                            {
                                break;
                            }
                            System.Threading.Thread.Sleep(1000);
                        }
                //After the loop ends i am trying to cancel the operation of the background   //worker...but that seems useless.
                backgroundWorker1.CancelAsync();

        }
at System.Drawing.Image.get_FrameDimensionsList
uiCtx = SynchronizationContext.Current;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    //replay is an array of the chess moves that were made since the start of the game.

    foreach (KeyValuePair<int, int[]> item in replay)// count should be more than 2
    {
         if (!backgroundWorker1.CancellationPending)
         {
              // ...
              uiCtx.Post(o =>
              {
                  PrintPieces(codeFile.PieceState());
              ), null);

              System.Threading.Thread.Sleep(1000);
         }
         else
         {
              break;
         }

     }

 }