C#Windows窗体异步任务获取跨线程操作异常

问题描述

一个用Windows窗体捕获相机的小项目上,我遇到了跨线程无效异常。我正在使用异步任务,但是在不禁用跨线程异常的情况下,无法找到从任务例程更新PictureBox元素的正确方法。避免这种情况的正确方法是什么?我尝试了Invoke所需的逻辑,但随后MainForm元素出现了相同的异常

 private void InitCameraBtn_Click(object sender,EventArgs e)
        {            
            if (InitCameraBtn.Text.Equals("Init Camera"))
            {
                StartCamera();
                InitCameraBtn.Text = "Stop Camera";
                isCameraRunning = true;
            }
            else
            {
                capture.Release();
                InitCameraBtn.Text = "Init Camera";
                isCameraRunning = false;
            }
        }

private async void StartCamera()
        {
            //cameraThread = new Thread(new ThreadStart(CameraThreadCallback));
            //cameraThread.Start();
            var r = await CameraThreadCallback();
           
        }

 public async Task<int>  CameraThreadCallback()
        {
            return await Task<int>.Run(() =>
            {

                frame = new Mat();
                capture = new VideoCapture(0);
                capture.Open(0);

                if (capture.IsOpened())
                {
                    while (isCameraRunning)
                    {

                        capture.Read(frame);
                        image = BitmapConverter.ToBitmap(frame);
                        if (CameraBox.Image != null)
                        {
                            CameraBox.Image.dispose();
                        }
                        //CameraBox.Image = image;

                        setimage(image);
                    }
                }
                return 0;
            });
        }

private void setimage (Bitmap i)
        {
            //MainForm.CheckForIllegalCrossthreadCalls = false;
            CameraBox.Image = i;
            Thread.Sleep(500);         

        }

解决方法

您应使用以下方法更新“相机”框:

private void SetCameraBoxImage(Image image)
    {
        if (CameraBox.InvokeRequired)
        {
            var d = new SafeCallDelegate(SetCameraBoxImage);
            CameraBox.Invoke(d,new object[] { image});
        }
        else
        {
            CameraBox.Image = image;
        }
    }

因此,不要使用CameraBox.Image = value

,

我认为您正在尝试从另一个线程访问Windows窗体控件。在这种情况下,您需要进行线程安全的调用

public async Task<int> CameraThreadCallback()
{
    return await Task<int>.Run(() =>
    {
        frame = new Mat();
        capture = new VideoCapture(0);
        capture.Open(0);

        if (capture.IsOpened())
        {
            while (isCameraRunning)
            {
                capture.Read(frame);
                image = BitmapConverter.ToBitmap(frame);
                CameraBox.Invoke(new Action(() =>
                {
                    if (CameraBox.Image != null)
                    {
                        CameraBox.Image.Dispose();
                    }
                    CameraBox.Image = image;
                })):
            }
        }
        return 0;
    });
}