通常,当您访问线程中的控件时,您最终会遇到一些跨线程异常。在我的 C# WinForms 应用程序中,我有一个图片框和一个工具条标签,它们不会导致该异常。我不明白为什么,谁能给我解释一下?
这里有一些代码解释:
在主窗体中,我有一个图片框和一个工具条标签。此外,我还引用了另一个表单,它没有控件,也没有额外的源代码。然后在主窗体中有另一个与线程一起工作的对象。该线程可以引发三个不同的事件,主窗体订阅这三个事件。
- Event1 导致工具条标签更新(带有来自线程的一些信息)。
- Event2 导致图片框更新(使用来自线程的新图片)。
Event1 和 Event2 工作得很好。我不使用任何调用方法,我直接更改 Text 和 BackgroundImage 属性而没有跨线程异常。
- Event3虽然会造成麻烦。它应该显示另一种形式,但我收到了交叉治疗异常。只有当我使用 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);
}
}
}