2010-09-13 72 views
1

我有另一個question在我的PictureBox調用給我3種錯誤,一些偉大的答案特別來自Conrad Frix。所以它導致我找出我的問題在哪裏,但現在要解決它我不是100%確定。InvokeRequired在PictureBox上爲true。如何處理這個?

基本上我有一個Windows窗體計時器,它檢查某個事件是否爲真,如果是,那麼它告訴系統在事件(值)超過某個閾值2秒後發送一些數據。

我想我所有的計時器是創造我的PictureBox一個討厭的競爭狀態,我在幾個地方使用,以獲得從圖像:

new Bitmap(myPicBox.Image); 

等等

我讀的地方定時器的時間間隔至少應該是50.從33開始。我發現我可以做一個picCapture.InvokeRequired來查看它是否會基本死亡。我知道我需要使用委託,但只使用這些設置的東西...不是從一個圖像...不知道如何設置...我知道是什麼確實造成它,這是這個碼組合:

private void timer1_Tick(object sender, EventArgs e) 
    { 
      if(someCOnditionTrue) 
      { 

        TimerCallback tc = new TimerCallback(sendDataFast); //only 
         //doing all this so i can have the method run two seconds after  
         // the condition is detected to be true. 
        System.Threading.Timer t = new System.Threading.Timer(tc, null, 2000, Timeout.Infinite); 
      } 
    } 



    void sendDataFast(Object stateObject) 
    { 

     //using this so the execution is not haulted while the sending of data takes place. 
     EmergencyDelegate delEmergency = 
        new EmergencyDelegate(mic.sendEmergencyData); 

     Image imgclone; 

     if (picCapture.InvokeRequired) 
     {     
      Console.WriteLine("HFS Batman! its going to die "); 
     } 
     lock (lockObject2) //i admit no clue what im doing here and doesn't seem to help. 
     { 
      Image img = picCapture.Image; 
      imgclone = (Image)img.Clone(); 
     } 
     delEmergency.BeginInvoke(imgclone, null, null); //deep in the call to 
     //sendEmergencyData i get the **ParameterNotValid** almost everytime. 

     imgclone.Dispose(); //to free memory? 


    } 

按照我剛纔的問題,似乎不再獲得在timer1_tick事件的內存問題或其他錯誤...(內存不足的錯誤是一個)。

我認爲最大的問題是如何處理picCapture.InvokeRequired當我需要它的圖像數據?我敢肯定它的我做了timer1_click內螺紋計時器調用引起此....

回答

1

顧名思義,InvokeRequired意味着你需要訪問控制何時調用Invoke(或BeginInvoke)。

注意,這是Control.Invoke/Control.BeginInvokeInvoke/BeginInvoke這是目前在代表......雖然你需要爲了一個委託呼叫Invoke/BeginInvoke,只是爲了更多的混亂加進來。

查看Windows Forms section of my threading tutorial瞭解更多詳情。總體教程可以做更新,但我相信這一點是好的。在其他情況下,您可能還需要考慮使用BackgroundWorker,但在這種情況下,我認爲這可能與您無關。

+0

謝謝生病馬上檢查一下。我之前曾經使用過代表調用方法,但那是在我的「真正的工作」,我沒有代碼在這裏,所以不知道我在那裏做了什麼...已經有一段時間了。 – Codejoy 2010-09-13 06:19:25

+0

@Jon:關於http://www.yoda.arachsys.com/csharp/threads/shutdown.shtml的例子,真的有必要在'停止'變量上使用鎖嗎?它似乎只能通過Stop()調用設置,並且永遠不會被取消設置。只是問,因爲我使用寫了一個非常類似的類,但我沒有鎖定我的等效停止變量。 – SomethingBetter 2012-01-05 21:40:16

+0

@SomethingBetter:你可能需要它是易變的,或者你需要鎖定。否則,不能保證在一個線程中的集合會在另一個線程中看到。 – 2012-01-05 21:52:27

1

我認爲你對InvokeRequired有一個錯誤的理解。 InvokeRequired指示當前線程與UI線程不同,現在訪問控制狀態將不安全。如果是這種情況,那麼你必須使用Control.Invoke編組對UI線程的調用,然後訪問控制狀態。閱讀here on MSDN瞭解更多信息。

就你的情況而言,除非PictureBox圖像正在改變,否則我會建議你預先對圖像進行克隆並使用它。否則,您需要使用Control.Invoke

1

你有太多的線索會把它帶到一個好的結局。 Timer和委託的BeginInvoke()方法都將使用線程池線程。問題是PictureBox.Image屬性只是部分線程安全的。它一次只能被一個線程訪問。當代碼調用Clone()方法的同時,UI線程繪製圖像時,您的代碼將會異常死亡。

您的鎖語句無法解決問題,PictureBox正在訪問Image屬性而不使用同一個鎖。我強烈建議首先擺脫線程,使用System.Windows.Forms.Timer而不是System.Threading.Timer。它是在UI線程中引發的Tick事件。但是,這會使UI線程在事件運行時無響應,這取決於用戶需要多長時間才能看到該事件。超過100毫秒就成了一個問題。

唯一的另一種方法是嘗試使PictureBox控件線程安全。這在一定程度上是可能的。爲您的項目添加一個新類並粘貼下面顯示的代碼。編譯。將新的控件從工具箱的頂部放到表單上,替換現有的PB。注意,這只是一個部分解決方案,顯示動畫GIF或使用ImageLocation屬性仍然會彈出。使用提供的Clone方法而不是在Image屬性上調用Clone。

using System; 
using System.Drawing; 
using System.Windows.Forms; 

class MyPictureBox : PictureBox { 
    private object locker = new object(); 
    public new Image Image { 
     get { return base.Image; } 
     set { lock (locker) { base.Image = value; } } 
    } 
    public Image Clone() { 
     lock (locker) { 
      return (this.Image != null) ? (Image)this.Image.Clone() : null; 
     } 
    } 
    protected override void OnPaint(PaintEventArgs pe) { 
     lock (locker) { 
      base.OnPaint(pe); 
     } 
    } 
} 
+0

好吧我喜歡這樣看起來,讓我感覺更溫暖和模糊。我看到這個問題的線程太多,我無法解決這個問題,因此我無法確定。我使用的計時器(至少是主計時器)是一個窗體計時器。其他的是線程計時器和代表。我想要做的事情聽起來很容易,但顯然還有更多的事情比想象的更糟。我想我可以在我的窗體上使用這個新控件,並仍然通過該圖像屬性訪問圖像? – Codejoy 2010-09-13 14:45:58

+0

是的,這是意圖。嘗試一下。 – 2010-09-13 14:51:07