Nick Valeontis wrote:
I was writing a C# program this week. The program works okay in my pc (in
both debug and release builds) but realized that it would not work to other
pcs. It simply would close after displaying an "This program has encountered
an error etc etc etc.." popup.
I added some try, catch blocks and found that the error message was: "Object
reference not set to an instance bla bla". After spending some time to
locate the line that causes the problem, I again realized that the code was
generated by the designer! And .. that I have no idea at all of what is
really happening. The lines that cause the problem are:
this.Resize += new System.EventHandler(this.frmGraphics_Resize);
this.ResumeLayout(false);
frmGraphics function is:
private void frmGraphics_Resize(object sender, EventArgs e) {
UpdateControls();
}
UpdateControls is self explanatory. It checks if text in various controls of
the form should be updated.
Can anyone tell me why this code generates this error?
Note that if I change the lines
this.Resize += new System.EventHandler(this.frmGraphics_Resize);
this.ResumeLayout(false);
to
this.ResumeLayout(false);
this.Resize += new System.EventHandler(this.frmGraphics_Resize);
Then it will work okay.
So ... what is the catch??? :/ Does anyone have any idea?
Well, I would have to see the code for UpdateControls to be sure, but
let me hazard a guess.
Designer-generated code is run in a Form's constructor. At that point
in the process, the form doesn't have a window handle yet. That is, it
does not yet correspond to a real window on the screen. As such,
certain operations are illegal, and certain properties that don't
normally return null do in fact return null.
The way that the Designer wrote the original code:
this.Resize += new System.EventHandler(this.frmGraphics_Resize);
this.ResumeLayout(false);
I'm guessing that the ResumeLayour call causes the Form to arrange the
positions and sizes of controls on its surface and, perhaps, resize
itself accordingly. Since the Designer has already attached an event
handler for the Resize event, this may cause your frmGraphics_Resize
method to be called when ResumeLayout runs. Therefore, your method is
being called before the window handle is allocated, and maybe you're
trying, in effect, to use some property that doesn't have a value yet.
Again, I'm guessing, but I would suppose that the second ordering:
this.ResumeLayout(false);
this.Resize += new System.EventHandler(this.frmGraphics_Resize);
would cause all of the mucking about with control positioning and
window sizing to happen before the frmGraphics_Resize method subscribes
to the Resize event. So, the method will miss the first Resize (the
one that happens during construction when the window is sort of
half-built) and handle the second and subsequent Resizes (which
probably happen only after the window is loaded and so has a proper
window handle, etc).
All of this, of course is pure supposition on my part. The way to find
out if I'm right or just blowing smoke is to put a try...catch around
the UpdateControls call, like this:
try
{
UpdateControls();
}
catch (NullReferenceException nre)
{
MessageBox.Show(String.Format("UpdateControls caused exception:
{0}", nre));
}
This should show you a message box pinpointing the exact line where the
exception occurs. I think that you'll find that you're doing some
operation or using some property that isn't valid until the window is
fully constructed, during the Load method. If you find that that's the
case, you could always try this:
private void frmGraphics_Resize(object sender, EventArgs e) {
if (this.IsHandleCreated) {
UpdateControls();
}
}
to see if it sorts things out.