Thursday, 17 March 2016

c# - Why can I access controls from a form in a thread without cross thread exception?



Usually, when you access controls in a Thread you end up with some cross thread exceptions. In my C# WinForms Application I have a picture box and a toolstriplabel which do not cause that exception. I don't understand why, can anybody explain this to me?



Here some code explanation:



In the main form I have a picturebox and a toolstriplabel. Also I have a reference to another Form, which has no controls and no additional source code. And then in the main form there is another object which works with a thread. This thread can raise three different events and the main form is subscribed to these three events.





  • Event1 causes the toolstriplabel to update (with some information from the thread).

  • Event2 causes the picturebox to update (with a new picture from the thread).



Event1 and Event2 work perfectly fine. I do not use any invoke methods, I directly change Text and BackgroundImage properties without cross thread exception.




  • Event3 though makes troubles. It is supposed to show the other form but I receive the cross therad exception. It works only if I use a BeginInvoke to show the form.




Why is that?



Edit:



The multithreading is done by an MJPEGStream object. I subscribe the NewFrame method of that MJPEGStream object.



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;
}
}



And here's the CAM class:



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);
}
}

}

Answer



You won't get cross thread exception, but it doesn't mean that this is a safe operation. There is always a possibility for your control to go unstable. You just don't know when it will happen.



See the following explanation from Microsoft.
http://msdn.microsoft.com/en-us/library/ms171728.aspx




Access to Windows Forms controls is not inherently thread safe. If you

have two or more threads manipulating the state of a control, it is
possible to force the control into an inconsistent state. Other
thread-related bugs are possible, such as race conditions and
deadlocks. It is important to make sure that access to your controls
is performed in a thread-safe way.



No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...