Error when calling Form.Show() a second time - c#

I have a main form with a button.
OnClick of that button does the following...
Form AllBook = new Form();
//Does some other processing and SQLReader querying.
AllBook.Show();
Afterwards I close the form. When I try to show it again I receive this error.
System.ObjectDisposedException: 'Cannot access a disposed object.
Object name: 'Form'.'
// objects
Form AllBook = new Form();
ComboBox booksList = new ComboBox();
ComboBox chapters = new ComboBox();
Panel topPannel = new Panel();
Panel txtPannel = new Panel();
TextBox mainText = new TextBox();
private void button1_Click(object sender, EventArgs e)
{
// add objects to form
AllBook.Controls.Add(topPannel);
topPannel.Controls.Add(booksList);
// get combobox items from another Method
int chapterCount = countChapters(43);
for (int i = 1; i <= chapterCount; i++) {
chapters.Items.Add(i);
}
topPannel.Controls.Add(chapters);
AllBook.Controls.Add(txtPannel);
txtPannel.Controls.Add(mainText);
AllBook.Show();
}
// count books chapters
public int countChapters(int bookNum) {
int chapter = 0;
switch (bookNum) {
case 1:
chapter = 50;
break;
case 2:
chapter = 40;
break;
case 3:
chapter = 27;
break;
case 4:
chapter = 36;
break;
.....
}

#H.G. Sandhagen and #LarsTech are correct.
Closing should dispose of the form. If you want to show it again you need to...
Form AllBook = new Form();
AllBook.Show();
...every time.
Edit: Adding further clarification.
Closing the form in a way calls Disopose() as well.
Source:
When a form is closed, all resources created within the object are
closed and the form is disposed. You can prevent the closing of a form
at run time by handling the Closing event and setting the Cancel
property of the CancelEventArgs passed as a parameter to your event
handler. If the form you are closing is the startup form of your
application, your application ends.
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.form.close?view=netframework-4.7.2

By default, closing a form will dispose it. But you can change this behavior by overriding the Closing event.
So you should either:
Create a new instance of your form each time you show it, and allow WinForms to dispose it when the user closes it; or
Override the Closing event, so that closing causes the form to get hidden instead of disposed, at which point you'll be able to show the same form multiple times:
private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
Hide();
e.Cancel = true;
}
Note that if you choose the second option, it will be up to you to call Dispose() on the form when you're done with it.

When the form is closing it automatically gets disposed, So you can refresh it before showing it again by using:
Allbook.Refresh();

Related

Update Controls in Form 1 from Form 2 that was Created by Form 1

I checked and found this article that is referred to MANY times in this type of question, and it is NOT the answer I want...
I have a form, Form_Main frmMainPage, it creates Form_Status frmStatus.
When it does so, I disable the controls on frmMainPage so the user can't mess with things while things are processing.
When things are done processing they can close the frmStatus window to go back to frmMainPage to continue working. I cannot re-enable the controls from frmStatus. I tried to use the frmMainPage_Enter, but it goes crazy when it first loads, so that isn't really an option.
I have the following in Form_Main.cs
public void EnableForm() {
this.gridData.Enabled = true;
this.txtLocation.Enabled = true;
this.txtSupplier.Enabled = true;
this.txtItem.Enabled = true;
this.FillTable("", "", "");
}
When I use this (per article above):
private void btnClose_Click(object sender, EventArgs e) {
Form_Main f2 = new Form_Main();
f2.Show();
f2.EnableForm();
this.Close();
}
It creates a second Form_Main, which is not what I want. I want to know how to change the controls in the existing form.
Edit: No, it is not this that was also suggested. Most of the answers deal with changing controls on Form 2 from Form 1 when Form 2 is created by Form 1. In my case I need to do the opposite and change controls on Form 1 FROM Form 2, which was created by Form 1. Kind of a circular thing.
I can think of a couple of ways to do this. First (and most common) is to show the second form modally (which means that the first form's code pauses while the second form's code is running):
private void button1_Click(object sender, EventArgs e)
{
var statusForm = new frmStatus();
// ShowDialog will prevent frmMainPage from being accessible.
// This form's code will pause at the next line until the second form is closed
statusForm.ShowDialog();
}
There are occasions where you want to have both forms accessible at the same time. If this is the case, another method would be to add an event handler for the second form's FormClosed event, where you can re-enable the controls on the first form. This will allow both forms to be accessed at the same time:
private void button1_Click(object sender, EventArgs e)
{
var statusForm = new frmStatus();
// Add an event handler for the second form's FormClosed event, and
// put code in that event handler to re-enable controls on this form
statusForm.FormClosed += statusForm_FormClosed;
// Disable our controls on this form and show the second form
DisableForm();
statusForm.Show();
}
private void statusForm_FormClosed(object sender, FormClosedEventArgs e)
{
// When the second form closes, re-enable controls on this form
EnableForm();
}
private void DisableForm()
{
this.gridData.Enabled = false;
this.txtLocation.Enabled = false;
this.txtSupplier.Enabled = false;
this.txtItem.Enabled = false;
}
public void EnableForm()
{
this.gridData.Enabled = true;
this.txtLocation.Enabled = true;
this.txtSupplier.Enabled = true;
this.txtItem.Enabled = true;
this.FillTable("", "", "");
}
you dont need to do this disable enable.
you just need to show your new from with ShowDialog(); like this:
frmStatus.ShowDialog();
instead of just:
frmStatus.Show();

C# Close windows form

I am opening up another form when a button is clicked, but can't decide how to close the current form when doing this. This is the code:
private void nextSportButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < Form1.sportsAdded; i++)
{
if (Form1.sportOpened == i)
{
Form1.IDNumber = Form1.sportIDArray[i];
OutputForm OutputForm = new OutputForm();
OutputForm.ShowDialog();
}
this.Close();
}
}
Calling OutputForm.ShowDialog() waits until OutputForm is closed and only then returns to execute further code. You want to use OutputForm.Show() instead.
Note: If "this" is the main form (the first form shown) of your application, closing "this" will terminate the whole application.
Use this.Hide(); instead of this.Close(); and using this.Close(); inside a for loop should throw an exception.
first hide current form don't close after open your new form,
this.Hide();
Form1.IDNumber = Form1.sportIDArray[i];
OutputForm OutputForm = new OutputForm();
OutputForm.ShowDialog();

C# Forms Show/Hide

In VB.NET, you can freely Hide/Show/ShowDialog (for a fresh form). But in C#, you always have to create new form instance to do this. Even your previosly hidden form can't show back, you have to create new instance again. Resulting in your previously hidden form will run as background process until you kill it.
My question is how can I create a function that will unhide a form that doesn't need a new instance when I close the current form using the default exit in form's title bar.
Edit: I solved it on my own. It's just confusing. And what difference between c# and vb.net is that I never have to use form_closed in vb.net. Why do I always see it in c#.
You can always display an hidden form in C#. There are many ways to this.
For example you could check the Application.OpenForms collection that keeps track of all forms owned by your application and still not closed. (An hidden form is not closed). This approach means that you need to identify you form between the ones included in the collection OpenForms
MyFormClass f = Application.OpenForms.OfType<MyFormClass>().FirstOrDefault();
if ( f != null) f.Show();
Another approach, more lengthy, is to keep track yourself of the form to hide/show with a variable inside your application. This requires extra care in handling correctly the various situations in which you global variable becomes invalid (what if the user closes effectively the form instead of hiding it?)
This is an example that you can test easily with LinqPAD
// Your form instance to hide/show
Form hidingForm = null;
void Main()
{
Form f = new Form();
Button b1 = new Button();
Button b2 = new Button();
b1.Click += onClickB1;
b2.Click += onClickB2;
b1.Location = new System.Drawing.Point(0,0);
b2.Location = new System.Drawing.Point(0, 30);
b1.Text = "Hide";
b2.Text = "Show";
f.Controls.AddRange(new Control[] {b1, b2});
f.ShowDialog();
}
void onClickB1(object sender, EventArgs e)
{
// Hide the global instance if it exists and it is visible
if(hidingForm != null && hidingForm.Visible)
hidingForm.Hide();
}
void onClickB2(object sender, EventArgs e)
{
// Create and show the global instance if it doesn't exist
if (hidingForm == null)
{
hidingForm = new Form();
hidingForm.Show();
// Get informed here if the user closes the form
hidingForm.FormClosed += onClosed;
}
else
{
// Show the form if it is not visible
if(!hidingForm.Visible)
hidingForm.Show();
}
}
void onClosed(object sender, FormClosedEventArgs e)
{
// Uh-oh.... the user has closed the form, don't get fooled...
hidingForm = null;
}
Well, OpenForms seems a lot better.

Resize all the windows of an application

I am creating a Windows app that will have multiple forms in it. Initially, I have set WindowState Maximized for all.
My problem here is that when I minimise one form, size of the other forms stay same. So, if I minimize the main screen go to the next screen, the size of the next screen remains unchanged. All I need to do is change size of all the windows at once.
I tried this:
Mainscreen mainscreen = new Mainscreen();
this.WindowsState = mainscreen.WindowsState;
But I am finding a way to do it for all screens.
A very ugly demo for your reference
private List<Form> Windows { get; set; }
public Form1()
{
InitializeComponent();
this.Text = "Main Window";
this.Windows = new List<Form>();
var defaultSize = new Size(200, 100);
for (var i = 0; i < 3; i++)
{
var form = new Form() { Size = defaultSize, Text = "Resize Me" };
var suppressEvent = false;
form.SizeChanged += (sender, e) =>
{
if (suppressEvent)
return;
suppressEvent = true;
defaultSize = (sender as Form).Size;
foreach (var otherForm in this.Windows)
{
if (otherForm != sender as Form)
otherForm.Size = defaultSize;
}
suppressEvent = false;
};
this.Windows.Add(form);
form.Show();
}
}
If the minimization is the concern and all sub forms launch from a previous form the quickest way would be to have the main form be the owner of the sub form.
If you make a simple project with two forms Form1 and Form2 and add a button onto Form1 that launches Form2 it would look like the following.
private void button1_Click(object sender, EventArgs e)
{
Form2 lForm = new Form2();
lForm.Show(this);
}
Passing "this" (which is reference to Form1) into the constructor of show will make sure that when it minimizes the subform (Form2) will also minimize. You can also change the setting of Form2 and set
lForm.ShowInTaskbar = false;
if you wanted to help make it clear that all of the forms are tied together.
If you are instead talking about having all forms maintain the same size regardless of who started the change and what the size ends up being then it gets a bit trickier and the simplest way would be to make a form manager of some sort that listens to the OnSizeChanged event and updates all forms whenever any form updates. Keep in mind with this that you'll also need to have a test in the form to know whether or not it is the one that started the update otherwise you would get in a sort of infinite loop where Form1 updates causing Form2 to update which then sends out another message which tries to make Form1 update etc...

Disable And Change Button Image On Click in C#

I have a button that on click I would like to be disabled and it's background image to be changed to null here is the code I have that happens on button click
private void levelOne1001_Click(object sender, EventArgs e)
{
levelOne1001.Enabled = false;
levelOne1001.BackgroundImage = null;
scoreClass.genRandomNumber(100);
scoreClass.valOfQuestion = 100;
q1001 = true;
openQuestionForm();
}
And here is the code from openQuestionForm();
private void openQuestionForm()
{
QuestionForm qForm = new QuestionForm();
scoreClass.iCount++;
qForm.Show();
this.Hide();
}
And here is where I call this form back up
Level1Form l1Form = new Level1Form();
l1Form.Show();
How the process works is Button on Original form is clicked goes to a Question form, button on Question form is clicked it goes back to Original Form. But when I go back to the original form the button is still enabled and the image is still there. Is there any way to fix this?
EDIT: Forgot to say this was in WinForms
You are instantiating a new Level1Form, so it's returning to its default state, causing the button to return to its default state. There are a few possible approaches:
Add a parameter to Level1Form's constructor that indicates what state the button should be in, something like
Level1Form(bool enableButton) {
initComponent();
if(!enableButton) {
levelOne1001.Enabled = false;
levelOne1001.BackgroundImage = null;
}
}
Or, grab the same form again and reuse it. You will need to keep a reference to it somewhere and tell it to show itself again. Alternately, you can grab it out of Application.OpenForms
You're creating a new Level1Form instance, which has nothing to do with the existing instance that you modified.
You need to re-show the original instance.
You need to remember your initial form instance in a member outside the method and call show on it.
Level1Form l1Form;
private void FirstTimeCreate()
{
l1Form = new Level1Form();
}
private void Reshow()
{
l1Form.Show();
}
First add ImageList1 to your design page. Then click on the arrow on top of the imageList, then click "choose images" and add all the different kind of images that you want your button to change upon clicking on it. Then write the below code:
int im = 3;
private void levelOne1001_Click(object sender, EventArgs e)
{
levelOne1001.BackgroundImage = imageList1.Images[im];
switch (im)
{
case 0:
case 1:
case 2:
im++;
break;
default:
im =0; // assuming you have 3 images; if you are at image 3 and click then let it go to image with index 0 (which is the beginning).
break;
}
// levelOne1001.Enabled = false; // you can add this code above as you see fit
}

Categories