Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

C#

StackOverflowException when creating a Form object.

Hi!

So, I am currently in the midst of writing a GUI application in C# and I figured that I would need a Input Prompt form so I decided to go ahead and make one.

I did look up a tutorial on how to do it, as I am not very experienced in creating C# GUI's at this moment in time, and I managed to find a thread on StackOverflow with quite a high rated solution in it. So, I got to work typing out that code and understanding it and it seemed like it was going to work fine.

However, when I run the program I experience a StackOverflowException and Visual Studio points me towards this line of code.

Form prompt = new Form();

Do any of you guys know why this would be happening? Thank you very much in advance to anyone who helps.

Full Code

PromptInput.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GuessTheNumberGameGUI
{
    public class PromptInput : Form
    {
        public static string ShowDialog(string text, string caption, string buttonText)
        {
            // Instantiates a new form.
            Form prompt = new Form();

            // Sets the forms width and height.
            prompt.Width = 500;
            prompt.Height = 150;

            // Sets the forms border style.
            prompt.FormBorderStyle = FormBorderStyle.FixedDialog;

            // Sets the forms text to the caption that is passed into the ShowDialog() method.
            prompt.Text = caption;

            // Sets the form to start in the center of the screen when it is loaded.
            prompt.StartPosition = FormStartPosition.CenterScreen;

            // Creates a label and positions it within the form.
            Label textLabel = new Label();
            textLabel.Left = 50;
            textLabel.Top = 20;
            textLabel.Text = text;

            // Creates a new textbox, positions it and sets it's width.
            TextBox textBox = new TextBox();
            textBox.Left = 50;
            textBox.Top = 50;
            textBox.Width = 400;

            // Creates a new button, sets it's text, sets it's width and positions it.
            Button confirmationButton = new Button();
            confirmationButton.Text = buttonText;
            confirmationButton.Left = 350;
            confirmationButton.Width = 100;
            confirmationButton.Top = 70;
            // Sets the DialogResult for when the button is clicked. In this case it is 'OK'.
            confirmationButton.DialogResult = DialogResult.OK;
            // Sets the form to close when the button is pressed.
            confirmationButton.Click += (sender, e) => { prompt.Close(); };

            prompt.Controls.Add(textLabel);
            prompt.Controls.Add(textBox);
            prompt.Controls.Add(confirmationButton);
            prompt.AcceptButton = confirmationButton;

            if (textBox.Text != "") {
                return textBox.Text;
            } else {
                ShowDialog(text, caption, buttonText);
            }
            return "";
        }
    }
}

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GuessTheNumberGameGUI
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GuessTheNumberGameGUI
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

            PromptInput.ShowDialog("Test Text", "More Test Text", "Button Text");

        }
    }
}

2 Answers

Steven Parker
Steven Parker
229,744 Points

Without actually bulding it, the first thing I notice is:

        public static string ShowDialog(string text, string caption, string buttonText)
        {
            // Instantiates a new form.
            Form prompt = new Form();

            // ... a bunch of code to create and add controls (including textBox) ...
            // ... and then this test:

            if (textBox.Text != "") {
                return textBox.Text;
            } else {
                ShowDialog(text, caption, buttonText);  // <-- note recursive call here
            }

I don't see anywhere between the creation of the form and the test where textBox would acquire any text, and if it is stil empty, the else of the test would cause the function to run itself. This would continue happening over and over, and since the new operation allocates stack space, it would make sense that it would eventually (in computer terms, instantly to the observer) overflow at one of them.

I'm wondering if there is something missing before that test that would include a call like this:

            prompt.ShowDialog();

This would display the form as a modal dialog and wait for user interaction, which would presumably include entering something into textBox. Even if that resolves the issue, I'd still question the use of the recursion and consider creating a loop instead.

Awesome, that helps a lot! I can now see where the problem is coming in and how I can go about fixing it.

However, I thought this dialog would stay open until it was shut by the user so how can I go about keeping it open until a valid input is entered?

Thank you very much for your help so far!

Steven Parker
Steven Parker
229,744 Points

Dialogs should stay open until some user action is performed, such as pressing the confirm or cancel button or pressing the Enter key on the keyboard, unless a timed function is set up to close it (and there's nothing like that here).

What is causing it to close?

....and remember to select a "best answer". :)

As far as I'm aware the only time the Form is explicitly told to close is when the button is pressed. It may be somewhere else and I am just missing it but I expected the form to stay open.

confirmationButton.Click += (sender, e) => { prompt.Close(); };

However, the form might auto close because I am returning a value straight away without the button being pressed.

As far as I'm aware the only time the Form is explicitly told to close is when the button is pressed. It may be somewhere else and I am just missing it but I expected the form to stay open.

confirmationButton.Click += (sender, e) => { prompt.Close(); };

However, the form might auto close because I am returning a value straight away without the button being pressed.

Steven Parker
Steven Parker
229,744 Points

The call to prompt.ShowDialog(); should wait until the user action is performed. The prompt form itself should be event-driven by the click handler you established.

How exactly would be the best way to go about doing that though when the user action needs to be done on the dialog?