C# 刷新PictureBox导致ArgumentException参数无效

C# 刷新PictureBox导致ArgumentException参数无效,c#,winforms,thread-safety,C#,Winforms,Thread Safety,我一辈子都搞不清楚这件事。我正在修改PictureBox指向的位图。基本上是有人在picturebox上拖动图像,图像会被更新,看起来就像是在picturebox上拖动一样。刷新picturebox时发生的情况是,我在Application.Run行上收到ArgumentException参数not valid错误,因此我花了一段时间才弄清楚到底是什么导致了这一情况,因为异常中没有更多信息 我创建了一个从picturebox派生的类,并重写了onpaint方法。它还有一个方法,RefreshIm

我一辈子都搞不清楚这件事。我正在修改PictureBox指向的位图。基本上是有人在picturebox上拖动图像,图像会被更新,看起来就像是在picturebox上拖动一样。刷新picturebox时发生的情况是,我在Application.Run行上收到ArgumentException参数not valid错误,因此我花了一段时间才弄清楚到底是什么导致了这一情况,因为异常中没有更多信息

我创建了一个从picturebox派生的类,并重写了onpaint方法。它还有一个方法,RefreshImage,用于调用自身并刷新自身

如果不刷新picturebox,则不会出现此错误,但picturebox图像从未更新

我有一个主循环在后面运行,它更新了逻辑。逻辑是当拖动鼠标时,图像偏移量会更新

循环完成逻辑后,它会尝试刷新picturebox。这就是我发现当我注释掉刷新行时,我没有问题,但picturebox从未更新过。我在自定义picturebox类中添加了一个名为UpdateImage的方法,该方法调用自身,然后刷新

重写的onpaint方法从自定义循环线程获取逻辑,并根据后端循环线程更新的偏移量更新位图

主窗体是在主线程上创建的,picturebox也是在主线程上创建的,我已经检查过了

调用工作正常,后端线程在刷新picturebox时调用主线程

注释掉刷新行会使错误消失,但看不到picturebox更新

那么,对于更好的方法或者错误的解决方案,有什么建议吗

这是Derived picturebox类的一部分

    public class PictureBoxEX : PictureBox
    {
        public int m_xoffset = 0;
        private Bitmap m_picture;
        public PictureBoxEX()
        {
            m_picture = new Bitmap(690, 600);
            this.Image = m_picture;
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);
            DrawBitmaps(); // updates the m_picture with another bitmap only in this class
            Graphics g = pe.Graphics;
            g.DrawImage(this.m_picture, new Point(0, 0));
        }
        public void RefreshImage()
        {
            if(this.InvokeRequired)
            {
                MethodInvoker d = new MethodInvoker(RefreshImage);
                this.Invoke(d);
            }
            else
            {
                this.Refresh();
            }
        }
    }
这里有一个主循环的想法

    private MainForm m_MainWindow; // derrives from Form

    private void MainThread()
    {
        int currTime = System.Environment.TickCount;
        int lastTime = currTime;
        while (Running)
        {
            currTime = System.Environment.TickCount;
            m_MainWindow.Update(currTime, lastTime);
            lastTime = currTime;

            Thread.Sleep(10);
        }
    }
下面是主窗口中更新方法的外观

PictureBoxEx m_LeftPictureBox;

public void Update(int currTime, int lastTime)
    {
        // do logic (all the logic is only working with primitive types, nothing to do with actual bitmaps
        this.m_LeftPictureBox.RefreshImage(); // if i comment this out, i will not get the exception, but it will not update the picturebox
    }
}
还有一件事,为什么picturebox在主窗体刷新时不刷新?或者可能是主要形式不令人耳目一新?我确信如果是这样的话,我会看到光标没有被清除。我在自定义picturebox类的onpaint方法中放置了一个断点,它在第一次创建时只被调用一次,但在那之后就没有了,所以我必须手动刷新它

编辑: 不确定我还能提供什么代码来帮助解决这个问题,但是如果我从后台线程调用这个函数(这个函数是以我创建的类的形式),我几乎会立即得到同样的异常。异常发生在this.Refresh()和主线程上(因此在调用它之后)。即使它在try-catch块中,异常仍然表示它未捕获并关闭我的应用程序

    public void InvokeRefresh()
    {
        if (this.InvokeRequired)
        {
            RefreshDelegate d = new RefreshDelegate(InvokeRefresh);
            this.Invoke(d, null);
        }
        else
        {
            try
            {
                this.Refresh();
            }
            catch { }
        }
    }

答案存在于评论中

问题在于调用 刷新需要从当前线程调用

this.Invoke((MethodInvoker)delegate
{
     this.m_LeftPictureBox.RefreshImage();
}

答案存在于评论中

问题在于调用 刷新需要从当前线程调用

this.Invoke((MethodInvoker)delegate
{
     this.m_LeftPictureBox.RefreshImage();
}

如果将InvokeRequired检查放在更新方法中会发生什么情况?好问题,我最初尝试过,同样的问题,我只是将invoke检查移动到自定义类中,虽然是为了清理更新方法,但谢谢,请发布完整的stacktrace和可能更多的代码。您的问题提到应用程序上的ArgumentException参数无效错误。运行行。这不应该与多线程问题有关。对于stacktrace来说不太可能。它类似于[external code]->Program.Run()->[external code],因此如果我不在表单或picturebox上调用refresh,则重写的onpaint只在首次创建时调用一次。如果我从后台线程调用窗体上的刷新(调用它),我会得到相同的异常,但是在主线程上的实际刷新调用中,如果将invokererequired检查放在Update方法中会发生什么?好问题,我最初尝试过,同样的问题,我只是将调用检查移到了自定义类中,以清理更新方法,谢谢,请发布完整的stacktrace和可能更多的代码。您的问题提到应用程序上的ArgumentException参数无效错误。运行行。这不应该与多线程问题有关。对于stacktrace来说不太可能。它类似于[external code]->Program.Run()->[external code],因此如果我不在表单或picturebox上调用refresh,则重写的onpaint只在首次创建时调用一次。如果我从后台线程调用表单的刷新(调用它),我会得到相同的异常,但是在主线程的实际刷新调用上