2016-11-01 190 views
0

我正在C#中使用Windows窗體打開一個新窗口,在C#中使用3,2,1倒數計時器創建一個簡單的相機窗體顯示拍攝的圖像。當第一個窗體閒置時,它最終會錯誤地顯示出來:「在System.Drawing.dll中發生了類型'System.InvalidOperationException'的異常,但未在用戶代碼中處理」。在System.Drawing.dll中發生類型'System.InvalidOperationException'的異常,但未在用戶代碼中處理

程序似乎表明該錯誤是pictureBox1.Image正在其他地方使用:

pictureBox1.Image = (Bitmap)eventArgs.Frame.Clone(); 

我不知道是什麼原因造成這一點。以下是與相機相關的所有代碼:

private static object locker = new Object(); 
    private FilterInfoCollection CaptureDevice; 
    private VideoCaptureDevice FinalFrame; 

    public Image File { get; private set; } 

    public void Form1_Load(object sender, EventArgs e) 
    { 

     FormBorderStyle = FormBorderStyle.None; 
     if (CaptureDevice == null) 
     { 
      lock (locker) 
      { 
       CaptureDevice = new FilterInfoCollection(FilterCategory.VideoInputDevice); 
      } 
     } 
     foreach (FilterInfo Device in CaptureDevice) 
     { 
      lock(locker) 
      { 
      comboBox1.Items.Add(Device.Name); 
     } 
      } 
     lock (locker) 
     { 
      comboBox1.SelectedIndex = 0; 
      FinalFrame = new VideoCaptureDevice(); 
      button1.PerformClick(); 
      button2.BringToFront(); 
     } 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     lock (locker) 
     { 
      button1.SendToBack(); 
      FinalFrame = new VideoCaptureDevice(CaptureDevice[comboBox1.SelectedIndex].MonikerString); 
      FinalFrame.NewFrame += new NewFrameEventHandler(FinalFrame_NewFrame); 
      FinalFrame.Start(); 
     } 



    } 

    private void FinalFrame_NewFrame(object sender, NewFrameEventArgs eventArgs) 
    { 
     lock (locker) 
     { 
      try 
      { 
       pictureBox1.Image = (Bitmap)eventArgs.Frame.Clone(); // <- Here is where the program indicates there is an error 
      } 
      catch (Exception exec) 
      { 
       Console.Write(exec); 
      } 
     } 
    } 
    private void Form1_FormClosing(object sender, FormClosingEventArgs e) 
    { 
     if (FinalFrame.IsRunning == true) 
     { 
      FinalFrame.Stop(); 
     } 
    } 

    private async void button2_Click(object sender, EventArgs e) 
    { 
     button2.SendToBack(); 
     button2.Hide(); 
     customLabel1.Show(); 
     await Task.Delay(200); 
     customLabel1.BringToFront(); 
     customLabel1.Refresh(); 
     await Task.Delay(800); 
     customLabel1.Refresh(); 
     customLabel1.Text = "2"; 
     await Task.Delay(800); 
     customLabel1.Refresh(); 
     customLabel1.Text = "1"; 
     await Task.Delay(800); 
     customLabel1.Refresh(); 
     customLabel1.Text = "3"; 
     customLabel1.Hide(); 
     button2.Show(); 
     button2.BringToFront(); 

     button2.Text = "CAPTURE"; 
     Form2 myPic = new Form2(); 
     myPic.pictureBox1.Image = (Bitmap)pictureBox1.Image.Clone() as Image; 
     myPic.ShowDialog(); 

    } 
+1

大多數視頻捕獲設備在工作線程上引發它們的「NewFrame」事件。這會觸發代碼中的線程錯誤,失敗將是隨機的。 PictureBox.Image屬性是*不是線程安全的,您必須使用BeginInvoke()來確保分配發生在UI線程上。在調用BeginInvoke()之前,請務必複製圖像。 Clone()還不錯,你可能需要使用Bitmap(Image)構造函數進行深層複製。你必須使用Dispose()來擺脫不再使用的位圖對象。 –

+0

我很欣賞這個迴應。然而,我有點困惑?爲什麼我會在調用BeginInvoke()之前複製pictureBox1.Image?我在NewFrame中做的唯一事情就是複製圖像,那麼BeginInvoke()會應用於任何東西嗎? – JonP

+0

不是pictureBox1.Image,你必須複製eventArgs.Frame。該位圖通常只在引發事件時有效。這就是爲什麼你必須首先使用Clone()。當您使用BeginInvoke()時,稍後會在事件處理程序停止運行後進行分配。你不想添加另一個線程錯誤:) –

回答

0

您必須處置先前使用的所有圖像。

//if (pictureBox1.Image != null) 
pictureBox1.Image.Dispose(); 
pictureBox1.Image = (Bitmap)eventArgs.Frame.Clone(); 
+0

我很感謝您的迴應!不幸的是,即使處置PictureBox1.Image如果不爲null,該程序仍然最終崩潰。 – JonP

+0

@JonP - 請參閱Hans Passant關於線程安全性的評論。 –

相關問題