Thread safety when using Aforge.NET and Windows Forms
本问题已经有最佳答案,请猛点这里访问。
我很难让aforge.net和我的Windows窗体应用程序一起玩。应用程序需要一个位图流来在自定义的PictureBox中显示视频,同时使用相同的流来跟踪使用颜色的对象。
我尝试锁定newframe事件,将图像从videosource复制到临时图像,如下所示,使用监视器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //Event for when a frame from the video is ready videoSource.NewFrame += (s, e) => { if (System.Threading.Monitor.TryEnter(updaterLock, 20)) { Bitmap old = currentImage; currentImage = (Bitmap)e.Frame.Clone(); currentImage.RotateFlip(RotateFlipType.RotateNoneFlipY); if (currentImage != null) { if (ImageUpdated != null) ImageUpdated(this, EventArgs.Empty); if (old != null) { old.Dispose(); old = null; } } else currentImage = old; System.Threading.Monitor.Exit(updaterLock); } }; |
上面的代码是一个类的一部分,该类返回一个单例实例,通过一个属性授予对当前映像的访问权。在这里可以找到整个类。在自定义控件中,按如下方式访问位图(DisplayControl类保存对rgbstream实例(位图流)的引用):
1 | Control.DisplayControl.Instance.ImageUpdated += (s, e) => this.Image = Control.DisplayControl.Instance.Bitmap; |
访问控件(this.image)的Image属性时引发异常(InvalidOperationException),其外观如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | System.InvalidOperationException was unhandled by user code HResult=-2146233079 Message=Cross-thread operation not valid: Control 'gridControl' accessed from a thread other than the thread it was created on. Source=System.Windows.Forms StackTrace: at System.Windows.Forms.Control.get_Handle() at System.Windows.Forms.Control.SetBoundsCore(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified) at System.Windows.Forms.Control.SetBounds(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified) at System.Windows.Forms.Control.set_Size(Size value) at SystemInterface.GUI.Controls.OccupancyGridControl.set_Image(Image value) in c:\Users\Stefan\SW505 oot\ProductCode\GUI\Controls\OccupancyGridControl.cs:line 64 at SystemInterface.GUI.Controls.OccupancyGridControl.<.ctor>b__0(Object s, EventArgs e) in c:\Users\Stefan\SW505 oot\ProductCode\GUI\Controls\OccupancyGridControl.cs:line 207 at Control.DisplayControl.<.ctor>b__0(Object s, EventArgs e) in c:\Users\Stefan\SW505 oot\ProductCode\Control\DisplayControl.cs:line 36 at System.EventHandler.Invoke(Object sender, EventArgs e) at Services.CameraServices.RgbStream.<.ctor>b__0(Object s, NewFrameEventArgs e) in c:\Users\Stefan\SW505 oot\ProductCode\Services\CameraServices gbStream.cs:line 121 at AForge.Video.DirectShow.VideoCaptureDevice.OnNewFrame(Bitmap image) at AForge.Video.DirectShow.VideoCaptureDevice.Grabber.BufferCB(Double sampleTime, IntPtr buffer, Int32 bufferLen) InnerException: |
有什么办法可以解决这个问题吗?谢谢)
我怀疑您的GUI订阅了ImageUpdated事件。将rgbstream方法更改为以下值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | private RgbStream(VideoCaptureDevice video) { videoSource = video; currentImage = null; updaterLock = new object(); if (videoSource == null) return; //Start the sensor and wait for it to be ready videoSource.Start(); while (!videoSource.IsRunning) { } //Event for when a frame from the video is ready videoSource.NewFrame += (s, e) => { if (System.Threading.Monitor.TryEnter(updaterLock, 20)) { Bitmap old = currentImage; currentImage = (Bitmap)e.Frame.Clone(); currentImage.RotateFlip(RotateFlipType.RotateNoneFlipY); if (currentImage != null) { if (ImageUpdated != null) { SynchronizationContext context = SynchronizationContext.Current ?? new SynchronizationContext(); context.Send(s => { ImageUpdated(this, EventArgs.Empty); }, null); } if (old != null) { old.Dispose(); old = null; } } else currentImage = old; System.Threading.Monitor.Exit(updaterLock); } }; } |