Implement using in c# without show dialogue win forms - c#

I am developing a winforms application with the code below to open new form :
using (Form1 f = new Form1(textBoxJobCardNo.Text, tf, tfh))
{
// System.GC.Collect();
f.FormBorderStyle = FormBorderStyle.None;
f.Left = sc[1].Bounds.Left;
f.Top = sc[1].Bounds.Top;
f.Height = sc[1].Bounds.Height;
f.Width = sc[1].Bounds.Width;
f.StartPosition = FormStartPosition.Manual;
labelerror.Visible = false;
textBoxJobCardNo.Clear();
f.ShowDialog();
}
I am using ShowDialog() to open new form. In place of ShowDialog() I want to use Show() without removing using statement because the using statement helps me to free memory after form close. If I use Show() then it will not hold on after Show() and moves out of using scope, which will close the form.
When i am using using my ram usage is constant when i am trying to do it with show without using it increase 2 mb on every form open.
Can't i hold control in using like show dialog with show.

If you don't show the form modally (using ShowDialog()), by default, it'll be disposed on closing. This is what the MSDN says:
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.
The two conditions when a form is not disposed on Close is when (1) it is part of a multiple-document interface (MDI) application, and the form is not visible; and (2) you have displayed the form using ShowDialog. In these cases, you will need to call Dispose manually to mark all of the form's controls for garbage collection.
So there's no need to call Dispose() (or use a using block) if the form is not modal and not MDI, it'll be freed when closed.
That said, this is an implementation detail that might change (although at this point in time, it's unlikely that it will), and it should be safe to call Dispose() multiple times if you want.

Put this line of code in the FormClosed Eventhandler of the form
this.Dispose();
aka:
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
this.Dispose();
}
The using block does nothing more than call dispose() on the resource you specify after the block ended. If you handle Disposing your Resources yourself you dont have to use the using block and your Resources are freed the way you specify, in this example after the Form has been closed.
Edit:
protected override void OnFormClosed(FormClosedEventArgs e)
{
base.OnFormClosed(e);
this.Dispose();
}

Form.Show() should be called without a using block because it will return immediately after showing the form, so that the user can access the new form and all other forms that are present. In a using block the newly shown form would be destroyed immediately after creation because of the automatic Dispose() call at the end of the block.
Form.ShowDialog() returns much later: after the Modal form is closed, so this will work fine in a using block.

Related

How can I open a WinForm multiple times?

I tried opening a second form using a button on my main form, but when I close the second window, I can't open it again.
I added the following code to my main form:
settings_window secondForm = new settings_window();
private void settings_button_Click(object sender, EventArgs e)
{
secondForm.Show();
}
But when I try to open the second form named settings_window the second time, I get the following error: System.ObjectDisposedException.
I found the following code to fix this but I don't know where to place it:
private void settings_window_FormClosing(object sender, FormClosingEventArgs e)
{
this.Hide();
e.Cancel = true; // Do not close the form.
}
You can avoid storing references of Forms and use a simple generic method that shows a Form when an instance of it already exists or creates a new one (and shows it) when none has been created before:
private void ShowForm<T>() where T : Form, new()
{
T? f = Application.OpenForms.OfType<T>().SingleOrDefault();
if (f is null) {
f = new T();
f.FormClosing += F_FormClosing;
}
f.Show();
BeginInvoke(new Action(()=> f.WindowState = FormWindowState.Normal));
void F_FormClosing(object? sender, FormClosingEventArgs e)
{
e.Cancel = true;
(sender as Form)?.Hide();
}
}
When you need it, call as ShowForm<SomeFormClass>(), e.g.,
ShowForm<settings_window>()
Note:
This code uses a local method to subscribe to the FormClosing event.
You can use a standard method, in case this syntax is not available.
BeginInvoke() is used to defer the FormWindowState.Normal assignment. This is used only in the case you minimize a Form, then right-click on its icon in the TaskBar and select Close Windows from the Menu. Without deferring this assignment, the minimized Form wouldn't show up again.
When the starting Form closes, all other Forms close as well
This code supposes nullable is enabled (e.g., see object? sender). If nullable is disabled or you're targeting .NET Framework, remove it (e.g., change in object sender)
Is secondForm a private field of the main form class?
It should work then.
Alternative solution is to show it as as modal - ShowDialog()
Also if you want to save some data in your second form, just use some data initialization from constructor, then saving to first/parent form.
I think you need to create a new instance of the form each time you want to open it. It will create a new instance of the settings_window form each time the button is clicked.
private void settings_button_Click(object sender, EventArgs e)
{
// Create a new instance of the form
settings_window secondForm = new settings_window();
secondForm.Show();
}
Your code shows a class that you have named settings_window, which gives us a hint about what its intended use might be. In general, for a form that behaves "like" a settings window, that you can call multiple times using the same instance, you can declare a member variable using this pattern:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
// Provide some means, like a menu or button, to show 'secondForm'
settingsMenu.Click += onClickSettingsMenu;
// Dispose the settings_form when the MainForm does.
Disposed += (sender, e) => secondForm.Dispose();
}
// By instantiating it here, its public default or persisted
// properties are immediately available, for example even
// while the main form constructs and loads the initial view.
settings_window secondForm = new settings_window();
private void onClickSettingsMenu(object? sender, EventArgs e)
{
if(DialogResult.OK.Equals(secondForm.ShowDialog()))
{
// Apply actions using the properties of secondForm
}
}
}
This is suitable for any form when you want to:
Repeatedly show and hide the form (e.g. a "Settings" form where the user can change the options multiple times).
Retrieve the default or the persisted properties of the form from the outset even if it's never been shown.
Use any of the form's public properties (e.g. GameLevel, SortType etc.) at any given moment while the app is running, even if the form isn't currently visible.
Display the form modally meaning that "no input (keyboard or mouse click) can occur except to objects on the modal form".
The reason it works is that calling ShowDialog (unlike calling Show) intentionally does not dispose the window handle, and this is to support of this very kind of scenario. The app is then responsible for disposing the resource when the app closes.
The Microsoft documentation for ShowDialog explains how this works.
Unlike non-modal forms, the Close method is not called by the .NET Framework when the user clicks the close form button of a dialog box or sets the value of the DialogResult property. Instead the form is hidden and can be shown again without creating a new instance of the dialog box. Because a form displayed as a dialog box is hidden instead of closed, you must call the Dispose method of the form when the form is no longer needed by your application.

Difference in using Modal and Non-Modal forms

I have a question regarding the using statement with Modal and Non-Modal Forms.
What I want to accomplish is the same behavior when I'm using the using statement.
Below an example that works perfectly with Modal forms.
Dictionary<string, string> input;
using (var window = new Form1()
{
window.ShowDialog();
if (window.DialogResult == DialogResult.Cancel)
{
return Result.Cancelled;
}
input = window.GetInformation();
}
When I change the ShowDialog() to Show() the whole form doesn't work anymore.
I've tried without the using statement but then I can't get information from my from like above.
Is there a way to achieve the exact same result but with form.Show() instead of using ShowDialog()?
Edit:
When I show the form from an external application with ShowDialog() it isn't deactivated when the external application is clicked. But I'm using the OnDeactivated event which doesn't trigger in this situation. So I tried with Show() and this seems to work.
If the question is why does the Show() not work when inside a Using statement, it is because Show() is non-modal and so program flow continues (i.e. doesn't wait for Form to close as ShowDialog() would). So flow continues to exit the Using, which disposes of objects created inside the Using, including the Form you have created. That's why it appears not to work.
Here's what I do to work around this issue.
I declare the Form I want to Show global to the class you are using:
private Form1 window;
and in the Function where I want to Show it:
if (window != null && !window.IsDisposed) window.BringToFront();
else
{
var window = new Form1();
window.Show();
// ... rest of your code here
}
Of course if you aren't using ShowDialog() you have to capture the result a different way. The way I prefer for this is to use the FormClosing event
add this when you instantiate the form:
window.FormClosing += window_FormClosing;
then add whatever code you want to capture the result in the event handler:
private void window_FormClosing(object sender, FormClosingEventArgs e)
{
Form1 window = sender as Form1;
// Your code here
}

what is the difference between show and showdialog in term of form closing in c#.net

I am working on winform application where I need to display a popup. I am currently doing it with ShowDialog() method. but due to change in requirement, I want to show it as non-dialog. So I have used show() method instead of showDialog().
my popup window is using windows webBrowse control as one of its child control.
my problem is when I use showDialog() method, everthing works fine.
but when I use show() method, and close the popup (once user is done with his work), show method() somehow calling dispose method of webBrowse control and this is preventing me to relaunch same popup again and giving me "Cannot access a disposed object" error.
Is this expected behavior in show() method or webBrowse control. if yes, then how Can I resolve it.
Note: PopUp dialog box is injected in presenter using DI so cannot inject popup after every dispose.
Thanks in advance.
By using showdialog() you can not go back to your parent form, by simply using show() you can go back, that's all
With Show(), your code proceeds to the line after the Show statement. With ShowDialog(), it does not.
You could try using Hide()instead of Close().
Put this in the constructor of your dialog window (this is a WPF example)
public Window()
{
this.Closing += Window_Closing;
}
And then cancel the close event and hide the window instead like this
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
this.Hide();
}
After that you should be able to reopen a closed window, beacuse it's not disposed but hidden. Problem with this is, that you have to manually clean the content of the window before reopening it, because otherwiese it contains the conten of the last use.

How to make c# don't call destructor of a instance

I have two forms and form1 needs to get data from form2, i use a parameter in form2 constructor to gets form1's instance like this:
public form2(Form form1) {
this.f = form1;
}
and in form1:
Form form2 = new Form(this);
But it seem form1 destruct was called when i closed form1. my question is how can i avoid this problem?
EDIT: I have many typing mistakes in my question, i'm so sorry, fixed:
I have two forms and form2 needs to get data from form1, i use a parameter in form1 constructor to gets form1's instance like this:
private Form f;
public form2(Form form1) {
this.f = form1;
}
and in form1:
Form form2 = new Form(this);
But it seem form1 destructor was called when i closed form2. my question is how can i avoid this problem?
from MSDN:
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.
As such, to prevent disposal of the resources, the only thing you can do is hide the form instead of closing it:
bool reallyClose;
protected override void OnClosing(CancelEventArgs e)
{
if (!reallyClose)
{
e.Cancel = true;
Hide();
}
base.OnClosing(e);
}
This will prevent the form being closed unless you manually set the reallyClose flag to true before closing the form.
You should make sure to close the form properly after you've finished using it.
Another option might be to decouple the data you need to retrieve from Form1 from the form itself.
In this case, form 1 cannot be destroyed until form2 is also closed. As long as form2 has a reference to form1, form1 will continue to exist. More likely, you are concerned with form1 being disposed. When form1 is closed, it will dispose itself. The object will still exist, but it will have released all its child controls and system objects such as window handles and drawing objects. Once a form has been disposed, it cannot be shown again, and all of it's controls will be inaccessible. If you try to use any of the visual components of a disposed form, it will throw an ObjectDisposedException. If you want to stop the form from being disposed, simply hide it rather than closing it. However, you should close it later once Form2 no longer needs it, otherwise it will stay around eating up memory and resources.
You should really factor whatever data you need out of both forms altogether, thereby avoiding the problem of coupled form constructors in the first place.

Controls disposed second time form is opened

The first time I open one of my child forms from the main form it opens normally. If I close the first instance of the child form and then reopen it however I get a crash the first time I try to call CreateGraphics() outside of the OnPaint() method. The exception I get is: "Cannot access a disposed object. Object name: 'MyControlClass'."
I've set breakpoints to monitor what's going on. Dispose() is called as expected the first time I close the form. When I start the form the second time MyControlClass's constructor is called, and the Dispose method isn't called prior to the exception. At the point of the exception this is still valid. Because of that I'm wondering if somehow it's actually the static component of MyControlClass that ended up being disposed; not the instance object.
I am creating a new copy of the form each time the button to show it is called. MyChildForm is a member held by my mt parentform and is also used to prevent multiple copies of the form from being opened at once.
ShowMyForm()
{
myChildForm = new myChildForm Form();
myChildForm.FormClosed += myChildFormFormClosed;
myChildForm.Show();
}
private void myChildFormFormClosed(object sender, FormClosedEventArgs e)
{
myChildForm = null;
}
The line of code that crashes: MyControlClass inherits from MyControlClassBase, which in turn inherits from MyControlClassBaseBase. This line of code is triggered by a mouse event in MyControlClassBase and is in MyControlClassBaseBase. The code after this would take a cached image of MyControl, display it using the newly created Graphics object, and then draw an overlay based on the mouse cursor position.
Graphics g = CreateGraphics();
PS Since I'm sure someone will ask: The rube goldberg in question is due to the utter fail that is fake 'transparency' in winforms in any but the most trivial cases and the fact that MyControlClass takes too long to paint to keep up with the mouse cursor; but that's a separate question entirely.
After a form is closed, it is disposed - meaning that it exists just to read fields.
If you want to show the same form again, create another instance or just hide it instead of closing.
MyForm f = new MyForm();
f.Show();
// After closed, it will be disposed.
So we need to do the same steps to show it again:
f = new MyForm();
f.Show();
Now you will get a brand new and identical form.
But to hide it when closed, you might need this code:
private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}
Note that it will not work with modal forms. (ShowDialog();)
(Thanks to Sorax) This will also not work with MDI children.

Categories

Resources