-3

I am getting a cross thread invalid exception on a small project with camera capture in windows forms. I am using an async task but can't find the correct way to update a PictureBox element from the task routine without disabling the cross thread exception. What is the correct way to avoid this? I tried the Invoke required logic but then I get the same exception with the MainForm element

 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);         

        }
RGolf77
  • 42
  • 5
  • `CameraBox.Image = i;` - this won't fly. There are more issues, but I guess this one is giving you the cross thread. – Fildor Aug 27 '20 at 14:34
  • You cannot write `async void` methods that are not event handlers. Proper usage of async/await isn't easy to learn, but you might get some ideas from https://blog.lextudio.com/how-to-replace-backgroundworker-with-async-await-and-tasks-80d7c8ed89dc All UI elements must be touched only on main thread. – Lex Li Aug 27 '20 at 15:01
  • I'd highly advise to make a separate class for all the camera related stuff. – Fildor Aug 27 '20 at 15:08
  • Yes, I plan on putting all the camera logic in a separate class. I just moved everything out to this test project to get the threading working – RGolf77 Aug 27 '20 at 16:15
  • Cross-thread exceptions must be avoided, not just suppressed. See duplicate for how to avoid them. If after solving the cross-thread exception you still see some other exception or other problem, _then that's another question_. If you want help with that or any other question, post a new question, and in that one make sure that you include a [mcve] that reliably reproduces the problem, as well as other details that explain what the problem is, what you've done so far to try to fix it, and what _specifically_ you need help with. – Peter Duniho Aug 27 '20 at 16:22

2 Answers2

0

You should update Camera box by using the below method:

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

So Instead of using CameraBox.Image = value use SetCameraBoxImage(value)

zafar
  • 1,965
  • 1
  • 15
  • 14
  • This works for the cross thread error, but I get a Parameter invalid exception on the main application.run – RGolf77 Aug 27 '20 at 15:56
0

I think that you are trying to access windows form control from another thread. In that case, you need to make a thread-safe call

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;
    });
}
guila
  • 33
  • 5