3
votes

Solution

I am now kicking myself over this, but you'll notice in the code below, that I am using a parameterized constructor for Form4. Standard procedure for a parameterized constructor in C# is to use :this() after the declaration (I think, at least for Forms). This calls the unparameterized/default constructor first, which contains InitializeComponent(), which sets up the form and its controls.

InitializeComponent() should most definitely not be in the parameterized constructor if you have used :this(), since it re-initializes your form with 'new' controls. This leads to an ambiguous state for your Form and controls, and the weird behavior I was getting.

Original Question

I have a form in which I would like the controls (including a textbox) to have initial values on first view. The values come from an SQL statement during the Form's construction, so I can't use the Form designer. This form's elements/controls were also copy-pasted from a nearly-identical form since that one is 'Add', and this one is 'Edit'

Problem is this: Using the debugger shows that I successfully get good data from the SQL, and that setting the textbox.Text succeeds, but when the form is displayed, it does not reflect the changes made. The answer here: https://stackoverflow.com/a/7830769/1655707 implies that the value can simply be set (presumably during initialization or load).

I've tried doing it during initialization, in the Load event, and the Shown event, and none of those work. Calling Refresh() and Application.DoEvents() also did nothing. Is there something I am missing? Some event that prevents this textbox from updating/displaying properly? Did copy-pasting the controls have unintended side-effects?

None of the controls I try and set this way display the changed value, but textbox was the simplest since it does not have indices to mess with.

    public Form4(int collIDFromParent, string collNameFromParent): this()
    {
        InitializeComponent();

        retCollID = collIDFromParent;
        retCollName = collNameFromParent;

        //Initialize these here so they activate on first use0
        button1.DialogResult = DialogResult.None;
        button2.DialogResult = DialogResult.Cancel;

        //PopulateEditData goes first for potential SQL failure
        PopulateEditData();

        textBox6.Text = "TEST";
    }

    private void Form4_Load_1(object sender, EventArgs e)
    {
        textBox1.Text = "TEST";
    }

    private void Form4_Shown_1(object sender, EventArgs e)
    {
        textBox2.Text = "TEST";
    }

And yes, they are setting different text boxes, but none of them work, so it makes little difference.

A typical textBox change handler. One might think that the way it's currently written might invoke some sort of resetting, but commenting out that one line does not change the behavior I'm concerned about.

    private void textBox6_TextChanged_2(object sender, EventArgs e)
    {
            retCollName = textBox6.Text;
    }
3
When you copy/pasted the controls, did you do that using the designer or from the code?CodingGorilla
@Coding Designer, so as to preserve the layout without having to specify the locations by handRuud A.
Have you looked at the designer code (usually hidden inside a region) to make sure that it updated everything to reference the form you pasted to and isn't still referencing the form you pasted from?CodingGorilla
Do the event handlers actually get called? I don't see where you hook up the event handlers (but that could be in the InitializeComponent().CodingGorilla
Instead of having multiple forms, you could set up an override on the constructor of the form with any options you need to retrieve the item from the database. Use the default constructor for the Add version, and the overload for Edit. Or, you could create an object out of the data you're retrieving and load the object before the form is created (a "defaulted" object for the Add), then pass that into a single constructor.krillgar

3 Answers

1
votes

With simple changes between functions (such as Add vs Edit), the core functionality of the Form is not going to change. The only core difference between the two functions you are trying to handle is a new object, and an existing object. Because of that, a single Form would be much better instead of two separate forms. It also saves a lot of work, and is one of the cores of OOP.

One other thing I would suggest would be to retrieve the data before you create the form. Create a data object that holds all of your properties you are retrieving from the database. Give that data class a Load method that takes in whatever identifier for which record you are looking for. Now you are set up for an easier time.

I'll make some default buttons here for the sake of examples, your experience may vary. :)

AddButton_Click(//default button click parameters) {
    Widget widget = new Widget();
    OpenWidgetForm(widget);
}

EditButton_Click(//default button click parameters) {
    Widget widget = new Widget();
    // You'll use the way you have now to determine which record to load,
    // and turn it to the id variable
    widget.Load(id);
    OpenWidgetForm(widget);
}

OpenWidgetForm(Widget widget) {
    frmWidget frm = new frmWidget(widget);
    frm.Show();
}

That code will be in whatever form you have that takes you to the Add/Edit forms.

Now in your Add/Edit form, you'll change it around like this:

private Widget _widget;

public frmWidget() {
    Widget widget = new Widget();
    _widget = widget;
    LoadWidget();
}

public frmWidget(Widget widget) {
    _widget = widget;
    LoadWidget();
}

public void LoadWidget() {
    // go through each of the properties of your object
    // and set the values to the Text properties of each Textbox.
    txtName.Text = _widget.Name;
}

With that you should be good to go. Let me know if you have any questions.

0
votes

I made a quick project to test this functionality. All three of these choices successfully set the value of the TextBox. You have an issue here that is not shown by the posted code. Either something is changing the TextBox values afterwards, or you're referencing the wrong TextBoxes. I just got done debugging a similar issue with our application. It turned out we somehow had two overlapping sets of TextBoxes (the ones we were actually using were underneath a set of empty TextBoxes).

    public Form1()
    {
        InitializeComponent();

        textBox1.Text = "TEST";
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        textBox2.Text = "TEST";
    }

    private void Form1_Shown(object sender, EventArgs e)
    {
        textBox3.Text = "TEST";
    }
0
votes

This may be a more trivial answer than this problem requires, but make sure you are in fact calling Controls.Add(textBox1). I noticed no one has mentioned this so far. Check in the Designer generated code first.

You will have to call it yourself if you're adding controls dynamically.