2009-06-29 34 views
30

私は連続して作成するスレッドをソース(実際にはデジタルカメラ)から取得し、パネル(パネル)に配置するC# GUIでの画像= IMG)InvalidOperationException - オブジェクトは現在他の場所で使用されています - 赤い十字形

(それはコントロールのコードビハインドであるとして、別のスレッドでなければなりません。

アプリケーションは動作しますが、私は(予測不可能なランダムな時間間隔で次のエラーを取得するいくつかのマシン上)

************** Exception Text ************** 
System.InvalidOperationException: The object is currently in use elsewhere. 

その後、パネルが赤い十字形に変わり、赤いX - これはプロパティから編集可能な無効な画像アイコンだと思います。イオンは機能し続けますが、パネルは更新されません。

このエラーは、コントロールのオンペイントイベントから来ています。ここで、私は画像に何か他のものを描画します。

私はそこにロックが、運を使用してみました:(

私は次のようにパネル上の画像を置く機能がある呼び出す方法:

if (this.ReceivedFrame != null) 
{ 
    Delegate[] clients = this.ReceivedFrame.GetInvocationList(); 
    foreach (Delegate del in clients) 
    { 
     try 
     { 
      del.DynamicInvoke(new object[] { this, 
       new StreamEventArgs(frame)}); 
     } 
     catch { } 
    } 
} 

これはデリゲートです:

public delegate void ReceivedFrameEventHandler(object sender, StreamEventArgs e); 
    public event ReceivedFrameEventHandler ReceivedFrame; 

これは、制御コードビハインド内部機能は、それに登録する方法である:

Camera.ReceivedFrame += 
    new Camera.ReceivedFrameEventHandler(camera_ReceivedFrame); 

は、私はまた、

は、誰もが、私はこのエラーを修正するか、少なくとも何らかの形でエラーをキャッチし、スレッドを作ることができる方法を知ってい

del.Method.Invoke(del.Target, new object[] { this, new StreamEventArgs(b) }); 

代わりの

del.DynamicInvoke(new object[] { this, new StreamEventArgs(frame) }); 

が、運を試してみましたもう一度パネルに画像を置く? GDI +のImageクラスはスレッドセーフではありませんので、私はこれが問題 使用ウィンドウの黄金ルールをマルチスレッドとメインスレッドの使用中のパネルを更新していると思う

答えて

0

が をpanel.Invokeこれは、クロススレッドの例外に

+0

メインスレッドのパネルを更新していますが、他のスレッドから更新し、パラメータとして画像を渡す関数を呼び出しています。 –

+0

他のスレッドからパネルを更新する関数を呼び出すと、関数自体にコンテキスト切り替えがない場合(たとえば、呼び出しを使用してメインスレッドに切り替えた場合)、メインスレッドではなく他のスレッドで更新が行われたことを意味します。 –

18

を克服すべきです。 Hovewerあなたが絵画や画像サイズを取得するための、たとえば、ロックあなたがイメージ・アクセスに必要なすべての時間を使って、InvalidOperationExceptionがを避けることができます。

Image DummyImage; 

// Paint 
lock (DummyImage) 
    e.Graphics.DrawImage(DummyImage, 10, 10); 

// Access Image properties 
Size ImageSize; 
lock (DummyImage) 
    ImageSize = DummyImage.Size; 

ところであなたは上記のパターンを使用する場合、呼び出しは、必要とされていません。

+0

onpaintイベントの内部で実行される関数は、パネル上に他のスレッドがパネル上で設定した画像の上に多くのものを描画します。描画される画像をロックするにはどうすればよいですか? –

+0

パネルがロックされていても機能しませんでしたが、まだエラーが表示されています –

+0

パネルをロックする必要はありません。使用する特定の画像をロックする必要があります。 – arbiter

2

同じCameraオブジェクトが何回か使用されているようです。

など。受信したフレームごとに新しいバッファを使用してみてください。ピクチャボックスが新しいフレームを描画している間、あなたのキャプチャライブラリは再びそのバッファを満たしているようです。したがって、より高速なマシンではこれは問題ではないかもしれませんが、遅いマシンでは問題となる可能性があります。

私は受信フレームごとに次のフレームを受信するように要求し、その要求でフレーム受信バッファNEWを設定する必要がありました。あなたがそれを行うことができない場合

は、新しいバッファに、第1のカメラから受信したフレームをコピーして、キューにそのバッファを追加、または単に2つの交互のバッファを使用し、オーバーランをチェック。 myOutPutPanel.BeginInvokeを使用してcamera_ReceivedFrameメソッドを呼び出すか、スレッドを実行して、キューをチェックします。新しいエントリがある場合は、新しいバッファをパネル上のイメージとして設定するメソッドを呼び出すmnyOutPutPanel.BeginInvokeを呼び出します。

さらに、バッファを受け取ったら、Panel Invokeメソッドを使用して画像の設定を呼び出します(キャプチャライブラリのスレッドではなく、ウィンドウスレッドで実行されることを保証します)。

次の例では、任意のスレッド(キャプチャライブラリまたは他の別のスレッド)から呼び出すことができます。

void camera_ReceivedFrame(object sender, StreamEventArgs e) 
{ 
    if(myOutputPanel.InvokeRequired) 
    { 
     myOutPutPanel.BeginInvoke( 
      new Camera.ReceivedFrameEventHandler(camera_ReceivedFrame), 
      sender, 
      e); 
    } 
    else 
    { 
     myOutPutPanel.Image = e.Image; 
    } 
} 
4

私は、同じエラーメッセージと同様の問題があったが、私は可能性がありますよう試みる、ビットマップをロックする」didnの私のために何かを修正する。それから私は静的なブラシを使ってシェイプを描いていることに気付きました。確かに、それはスレッドの競合を引き起こしていたブラシでした。

var location = new Rectangle(100, 100, 500, 500); 
var brush = MyClass.RED_BRUSH; 
lock(brush) 
    e.Graphics.FillRectangle(brush, location); 

これは私のケースと習得のために役立ちました:スレッドの競合が発生しているポイントで使用されているすべての参照タイプを確認します。

+1

私の場合、それはブラシでもありました。ちょうど楽しみのために私はフォントでそれを試しましたが、それは複数のスレッドから動作するようです。 –

関連する問題