通常、スレッド内のコントロールにアクセスすると、いくつかのクロススレッド例外が発生します。私のC#WinFormsアプリケーションには、その例外を引き起こさない画像ボックスとツールストリップラベルがあります。理由がわかりませんが、誰か説明してもらえますか?
ここにいくつかのコードの説明があります:
メインフォームには、ピクチャーボックスとツールストリップラベルがあります。また、コントロールや追加のソースコードがない別のフォームへの参照があります。そして、メインフォームには、スレッドで動作する別のオブジェクトがあります。このスレッドは3つの異なるイベントを発生させることができ、メインフォームはこれらの3つのイベントにサブスクライブされます。
- Event1により、toolstriplabelが更新されます(スレッドからの情報を使用)。
- Event2により、画像ボックスが更新されます(スレッドからの新しい画像で)。
Event1とEvent2は完全に正常に機能します。私はinvokeメソッドを使用せず、クロススレッド例外なしでTextプロパティとBackgroundImageプロパティを直接変更します。
- Event3は問題を起こします。他の形式を表示することになっていますが、crosstherad例外が発生します。BeginInvokeを使用してフォームを表示した場合にのみ機能します。
何故ですか?
編集:
マルチスレッドはMJPEGStreamオブジェクトによって実行されます。そのMJPEGStreamオブジェクトのNewFrameメソッドをサブスクライブします。
public partial class Form1 : Form
{
private CAM cam;
private PeekWindow frmPeekWindow;
public Form1()
{
InitializeComponent();
cam = new CAM();
cam.NewImageMessageEvent += new NewImageEventHandler(cam_NewImageMessageEvent);
cam.DetectionEvent += new DetectionEventHandler(cam_DetectionEvent);
cam.FpsChangedMessageEvent += new FpsChangedEventHandler(cam_FpsChangedMessageEvent);
cam.DetectionThreshold = (float)this.numDetectionThreshold.Value;
frmPeekWindow = new PeekWindow();
// without the next two lines, frmPeekwindow.Show() won't work if called in an event
frmPeekWindow.Show();
frmPeekWindow.Hide();
}
void cam_FpsChangedMessageEvent(object sender, FpsChangedEventArgs e)
{
lblFPS.Text = string.Format("fps: {0:0.0}", e.FPS);
}
void cam_DetectionEvent(object sender, DetectionEventArgs e)
{
if (chkEnablePeakWindow.Checked)
{
if (frmPeekWindow.InvokeRequired)
{
frmPeekWindow.Invoke((MethodInvoker)delegate()
{
frmPeekWindow.Show();
frmPeekWindow.setImage(e.Image);
});
}
else
{
frmPeekWindow.Show();
frmPeekWindow.setImage(e.Image);
}
}
}
void cam_NewImageMessageEvent(object sender, NewImageEventArgs e)
{
picStream.BackgroundImage = e.Image;
}
}
そして、これがCAMクラスです。
class CAM
{
private object lockScale = new object();
private MJPEGStream stream;
private Bitmap image;
public event NewImageEventHandler NewImageMessageEvent;
public event FpsChangedEventHandler FpsChangedMessageEvent;
public event DetectionEventHandler DetectionEvent;
// configure (login, pwd, source)
public CAM()
{
this.stream = new MJPEGStream("...");
this.stream.Login = "...";
this.stream.Password = "...";
this.stream.NewFrame += new NewFrameEventHandler(OnNewFrame)
}
private void OnNewFrame(object sender, NewFrameEventArgs ev)
{
try
{
FpsChangedMessageEvent(this, new FpsChangedEventArgs(10));
// get image
image = ev.Frame;
NewImageMessageEvent(this, new NewImageEventArgs(new Bitmap(image)));
DetectionEvent(this, new DetectionEventArgs(new Bitmap(image)));
}
catch (Exception ex)
{
Console.Out.WriteLine(ex.Message);
}
}
}