I have a form with a button, a label and a progress bar, so that when I click the button it creates an instance of class b to run a process. Once the process is done it will call an EventHandler to show "done" in the main form's label!
I created an event (SetStatusEvent) of a delegate (SetStatus) to do this. And it seems fine when I call this event outside the EventHandler (usbforProcessExited) but when I call it from usbforProcessExited it gives an error -
object reference not set to an instance of an object
main form
public partial class main : Form
{
b rsSet = new b();
public main()
{
InitializeComponent();
rsSet.SetStatusEvent += new RemoteS.SetStatus(updateStatus);
}
private void button1_Click(object sender, EventArgs e)
{
rsSet.FormatUSB();
}
private delegate void UpdateStatus(int i, string str, Color clr);
private void SetStatus(int i, string str, Color clr)
{
this.progressBar1.Value = i;
this.lbl_status.ForeColor = clr;
this.lbl_status.Text = str;
}
private void updateStatus(int i, String msg, Color color)
{
object[] p = GetInokerPara(i, msg, color);
BeginInvoke(new UpdateStatus(SetStatus), p);
}
private object[] GetInokerPara(int progress, string msg, Color color)
{
object[] para = new object[3];
para[0] = progress;
para[1] = msg;
para[2] = color;
return para;
}
}
class b
class b
{
public delegate void SetStatus(int i, string msg, Color color);
public event SetStatus SetStatusEvent;
System.Diagnostics.Process usbfor = new System.Diagnostics.Process();
public void FormatUSB()
{
usbfor.StartInfo.FileName = @"usbformat.bat";
usbfor.EnableRaisingEvents = true;
usbfor.Exited += new EventHandler(usbforProcessExited);
usbfor.Start();
}
public void usbforProcessExited(object sender, EventArgs f)
{
SetStatusEvent(100, "DONE", Color.Green); //ERROR HERE! (object reference not set to an instance of an object
}
}
Where is the problem?
The event is null, if there are no subscribers.
There are two solutions:
Initialize the event when declaring (dummy subscriber doing nothing):
public event SetStatus SetStatusEvent = delegate { };
Check the event for null before raising (in a thread-safe way):
public void usbforProcessExited(object sender, EventArgs f)
{
SetStatus setStatus = SetStatusEvent;
if (setStatus != null)
{
setStatus(100, "DONE", Color.Green);
}
}
You have a race condition:
usbforProcessExited
gets subscribed in the constructor of b
and might be invoked before you called rsSet.SetStatusEvent += new RemoteS.SetStatus(updateStatus)
.
You should only call usbfor.Start()
after you subscribed to SetStatusEvent
.
A related problem is that the event will run on another thread. You should set rsSet.SynchronizingObject
before starting the process so your event handler can modify the form without manually calling Invoke
/BeginInvoke
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With