1

PictureBox の呼び出しで別の質問があり、3 種類のエラーが発生しました。特にConrad Frixからいくつかの素晴らしい回答がありました。そのため、問題がどこにあるのかを突き止めることができましたが、今はそれを修正するために 100% 確実ではありません。

基本的に、いくつかのイベントが真であることをチェックする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 イベントでメモリの問題やその他のエラーが発生しないようです... (メモリ不足エラーは 1 つでした)。

最大の問題は、画像データが必要なときに picCapture.InvokeRequired をどのように処理できるかだと思いますか? timer1_click内のスレッドタイマー呼び出しがこれを引き起こしていると確信しています....

4

3 に答える 3

1

これをうまく終わらせるスレッドが多すぎます。Timer とデリゲートの BeginInvoke() メソッドは両方とも、スレッドプール スレッドを使用します。問題は、PictureBox.Image プロパティが部分的にのみスレッド セーフであることです。一度にアクセスできるスレッドは 1 つだけです。コードが Clone() メソッドを呼び出しているのとまったく同じタイミングで UI スレッドによって画像が描画されると、コードは例外で終了します。

あなたの lock ステートメントは問題を解決しません。PictureBox は同じロックを使用せずに Image プロパティにアクセスしています。System.Threading.Timer の代わりに System.Windows.Forms.Timer を使用して、最初にスレッド化を取り除くことを強くお勧めします。UI スレッドで Tick イベントが発生します。ただし、イベントの実行中に UI スレッドが応答しなくなります。それがユーザーに認識されるかどうかは、どれくらい時間がかかるかによって異なります。たとえば、100 ミリ秒を超えると問題が発生します。

他の唯一の方法は、PictureBox コントロールをスレッドセーフにすることです。それはある程度可能です。プロジェクトに新しいクラスを追加し、以下に示すコードを貼り付けます。コンパイル。ツールボックスの上部から新しいコントロールをフォームにドロップし、既存の PB を置き換えます。これは部分的な解決策にすぎないことに注意してください。アニメーション GIF を表示したり、ImageLocation プロパティを使用したりすると、依然として爆発します。Image プロパティで Clone を呼び出す代わりに、提供されている 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);
        }
    }
}
于 2010-09-13T11:21:19.570 に答える
1

その名前が示すように、コントロールにアクセスするときに(または)InvokeRequiredを呼び出す必要があることを意味します。InvokeBeginInvoke

これはControl.Invoke/Control.BeginInvokeであり、デリゲートに存在するものではないことに注意してください...ただし、 /を呼び出すInvoke/BeginInvokeにはデリゲートが必要ですが、混乱を招くだけです。 InvokeBeginInvoke

詳細については、私のスレッド チュートリアルの Windows フォームのセクションを参照してください。全体的なチュートリアルは更新で行うことができますが、このビットは問題ないと思います. 他の状況では、 の使用を検討することもできBackgroundWorkerますが、この特定のケースでは、それが適切である可能性は低いと思います。

于 2010-09-13T06:15:45.167 に答える
1

InvokeRequired について間違った理解をしていると思います。InvokeRequired は、現在のスレッドが UI スレッドと同じではなく、現在コントロールの状態に安全にアクセスできないことを示します。そのような場合はControl.Invoke、UI スレッドへの呼び出しをマーシャリングしてから、コントロールの状態にアクセスする必要があります。詳細については、MSDNのこちらを参照してください。

あなたの場合、PictureBox 画像が変更されていない限り、前もって画像のクローンを作成し、それを使用することをお勧めします。それ以外の場合は、を使用する必要がありますControl.Invoke

于 2010-09-13T06:21:55.390 に答える