- Home /
NullReferenceException in a GUI Dialog Method
WARNING: This post is very long. My problem is somewhat complicated and may require more time than i would hope... I apologize for that. However, I thank anyone who is willing to help! It is very much appreciated. Thank You! Anyways, please read this post in its entirety.
I'm coming across a NullReferenceException at the very beginning of game start. I'm also coming across a NullReferenceException that occurs every time FixedUpdate is called.
On Start Exception stack:
NullReferenceException: Object reference not set to an instance of an object
UAve.UAveLogger.ShowExceptionDiaglog (System.Exception exception, System.String message, UAve.MessageCallbackDelegate callback) (at Assets/UA/UAveLogger.cs:36)
UAve.GameControl.Start () (at Assets/UA/Game/GameControl.cs:87)
On Fixed Update Exception Stack:
NullReferenceException: Object reference not set to an instance of an object
UAve.UAveLogger.ShowExceptionDiaglog (System.Exception exception, System.String message, UAve.MessageCallbackDelegate callback) (at Assets/UA/UAveLogger.cs:36)
UAve.Player.PlayerControl.FixedUpdate () (at Assets/UA/Game/PlayerControl.cs:317)
Ironically, this exception occurs only during other exceptions. The reason for this is because the method UAveLogger.ShowExceptionDialog(exception, message, callback)
(shown below) is called every time there is an exception caught in a Try/Catch statement. That method is what is causing these NullReferenceExceptions.
ShowExceptionDialog Method:
public static void ShowExceptionDiaglog(Exception exception, string message, MessageCallbackDelegate callback)
{
if (exception == null)
throw new ArgumentNullException("exception");
if (message == null)
throw new ArgumentNullException("message");
if (callback == null)
throw new ArgumentNullException("callback");
shownMessageBoxes.Add(new UAveMessageBox("Uh oh! An exception occured...", exception.TargetSite.Name + ".\n\r" + message, UAveMessageBox.DialogButtons.Okay, new Vector2(-1, -1), callback));
}
Notice that i go through and check to see if each parameter passed into the method is null, and if it is, i throw an ArgumentNullException. (This SHOULD make it so that the NullReferenceException doesnt occur and an ArgumentNullException instead, but it doesn't).
Here is the entire UAveLogger component (yes it is attached to a game object in the scene):
public class UAveLogger : MonoBehaviour
{
private static List<UAveMessageBox> shownMessageBoxes = null;
public enum DialogResult
{
Okay,
Cancel,
Yes,
No
}
public static void ShowExceptionDialog(Exception exception, string message, MessageCallbackDelegate callback)
{
if (exception == null)
throw new ArgumentNullException("exception");
if (exception.TargetSite.Name == null)
throw new ArgumentNullException("exception.TargetSite.Name");
if (message == null)
throw new ArgumentNullException("message");
if (callback == null)
throw new ArgumentNullException("callback");
shownMessageBoxes.Add(new UAveMessageBox("Uh oh! An exception occured...", exception.TargetSite.Name + ".\n\r" + message, UAveMessageBox.DialogButtons.Okay, new Vector2(-1, -1), callback));
}
public void Start() { }
public void OnGUI()
{
if (shownMessageBoxes != null) //If the shownMessageBoxes list is null: do nothing. Otherwise: procede.
{
foreach (UAveMessageBox uamb in shownMessageBoxes) //Iterate through every UAveMessageBox in the shownMessageBoxes list
{
if (uamb.MessagePosition == new Vector2(-1, -1)) //Ignore this, it doesn't effect anything at the moment.
{
//Center message box on screen using Screen.width and Screen.height
GUILayout.BeginArea(new Rect(Screen.width / 2, Screen.height / 2, 300, 200)); //Begin messagebox area
GUILayout.BeginVertical(); //Begin primary text area
GUILayout.TextArea(uamb.DialogCaption); //The top of the message box will contain the dialog's caption.
GUILayout.TextArea(uamb.DialogText); //The center of the message box will contain the dialog's text.
GUILayout.BeginHorizontal(); //Begin button area
switch (uamb.DialogButton) //Switch between each possibility for uamb's dialog button field.
{
case UAveMessageBox.DialogButtons.Okay: //Show the "Okay" button if the case is DialogButtons.Okay
if (GUILayout.Button("Okay"))
{
shownMessageBoxes.Remove(uamb); //Remove the messagebox from the shownMessageBox List so that it doesn't get iterated and shown anymore.
uamb.messageCallback(DialogResult.Okay); //Call the callback delegate provided by the UAveMessageBox
}
break;
case UAveMessageBox.DialogButtons.OkayCancel:
if (GUILayout.Button("Okay"))
{
shownMessageBoxes.Remove(uamb);
uamb.messageCallback(DialogResult.Okay);
}
if (GUILayout.Button("Cancel"))
{
shownMessageBoxes.Remove(uamb);
uamb.messageCallback(DialogResult.Cancel);
}
break;
case UAveMessageBox.DialogButtons.YesNo:
if (GUILayout.Button("Yes"))
{
shownMessageBoxes.Remove(uamb);
uamb.messageCallback(DialogResult.Yes);
}
if (GUILayout.Button("No"))
{
shownMessageBoxes.Remove(uamb);
uamb.messageCallback(DialogResult.No);
}
break;
case UAveMessageBox.DialogButtons.YesNoCancel:
if (GUILayout.Button("Yes"))
{
shownMessageBoxes.Remove(uamb);
uamb.messageCallback(DialogResult.Yes);
}
if (GUILayout.Button("No"))
{
shownMessageBoxes.Remove(uamb);
uamb.messageCallback(DialogResult.No);
}
if (GUILayout.Button("Cancel"))
{
shownMessageBoxes.Remove(uamb);
uamb.messageCallback(DialogResult.Cancel);
}
break;
}
GUILayout.EndHorizontal(); //End button area
GUILayout.EndVertical(); //End primary text area
GUILayout.EndArea(); //End messagebox area
}
}
}
}
}
Here is the MessageCallbackDelegate delegate that is used for method callback:
public delegate void MessageCallbackDelegate(UAveLogger.DialogResult dr);
Here is the UAveMessageBox class that represents a GUI MessageBox:
public class UAveMessageBox
{
public enum DialogButtons
{
Okay,
OkayCancel,
YesNo,
YesNoCancel
}
public string DialogCaption;
public string DialogText;
public DialogButtons DialogButton;
public Vector2 MessagePosition;
public MessageCallbackDelegate messageCallback;
public UAveMessageBox(string caption, string text, DialogButtons dbuttons, Vector2 pos, MessageCallbackDelegate mcd)
{
this.DialogButton = dbuttons;
this.DialogCaption = caption;
this.DialogText = text;
this.MessagePosition = pos;
this.messageCallback = mcd;
}
}
Here is the method that is invoking ShowExceptionDialog at the very start (Found in GameControl.cs):
void Start()
{
try
{
//Some (Confidential) code that causes an Exception.
}
catch (Exception e)
{
UAveLogger.ShowExceptionDialog(e, e.StackTrace + "_;_\n\r" + e.Message, clErrorCallbackException);
}
}
Here is the FixedUpdate event that is invoking ShowExceptionDialog (Found in PlayerControl.cs):
public void FixedUpdate()
{
try
{
//Some (Confidential) code that causes an Exception.
}
catch (Exception e)
{
UAveLogger.ShowExceptionDialog(e, e.StackTrace + "_;_\n\r" + e.Message, clErrorCallbackException);
}
}
I think that is all the information needed to understand my problem in its entirety. Please Note that all of the clErrorCallbackException methods that are called don't do anything, they are empty methods.
Thank you for even putting in the effort to read all of this, I know that it's daunting.
If you believe that you have a solution to my problem, PLEASE REPLY!!! Even if you're not sure if it's a perfect solution, any help that can set me on the right track is appreciated!
Answer by Bunny83 · Oct 06, 2013 at 12:27 AM
Well, there are not much things left which can cause a null ref exception. Probably TargetSite
If the method that throws this exception is not available and [ ... ] the stack trace is a null reference, TargetSite also returns a null reference.
edit
the second thing is shownMessageBoxes, where do you create the List? You set it to null in the field initializer, but do you actually create it somewhere? You don't check it for null inside ShowExceptionDialog
Thank you! Youre correct, i never initialized the List. I must have made that error when i was converting the list from an event delegate to a List. I'll see if that fixes my error. Also, i will add an if statement that checks to see if TargetSite is null.
btw. this:
shown$$anonymous$$essageBoxes.Remove( ... )
inside a foreach loop through shown$$anonymous$$essageBoxes will throw an exception because the IEnumerator used by foreach will get invalide once the collection has changed inside the loop.
It's better to mark it for deletion and remove it in Update. Doing such things in OnGUI is in general not a good idea. There must be the same amount of GUI controls in the Repaint Event as you had in the Layout event. changing stuff inside OnGUI.
Next thing is it seems you show the message boxed on top of each other. That will give you additional problems because the bottom most dialog will respond first to input. A solution is to set GUI.enable to false for all message boxed except the last one. That way only the last and top most will react to mouseinput. Once it's closed the next in the chain will "get active".
It works! Now the exception dialog shows as it should. I appreciate your help.
@Bunny83 Oh i didn't see that comment. Alright i'll do those things. Thank you for the tips!
Your answer
Follow this Question
Related Questions
My OnGUI() Won't show the Button elements :( 0 Answers
I keep getting an error on my for loop. 1 Answer
Multiple Cars not working 1 Answer
why is my GUI script bugging other GUI scripts? 0 Answers
putting gui elements in fixedupdate 1 Answer