I have a WinForms application, And somewhere in the program user can bring up another form like pop up window for example an About Us form. I want the main form to be locked (eg User can not do anything in the UI of main form). And when that pop-up window is closed the main form would be return to normal state.
This is my code (I think I only miss the way of locking my main form)
private void buttonAbout_Click(Object sender, EventArgs e)
{
AboutUS abUs = new AboutUS();
abUS.Show()
this.LOCK!!! /* How to lock current form? */
abUS.FormClosing += delegate { /* How to Unlock main form */ };
}
Use Form.ShowDialog() instead of Form.Show().
Also see a related question.
Related
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.
This question already has answers here:
How to prevent clicks outside the current form?
(2 answers)
Closed 1 year ago.
I am creating an application where I have a Form 1 (Main Form). Inside this main form there is a button that opens up a different and smaller form (Form 2). I don't want to hide Form 1 when showing Form 2 but because of the size of Form 2, the user is able to click Form 1 hiding Form 2 with its size (not hidden like Form2.hide();) however this is something I don't want to do. I want to prohibit the user to click Form 1 if Form 2 is currently open. Is there any event or function I can use to do this? I have seen in it in other applications but I don't even know how to look for it.
In addition to using the ShowDialog method as suggested in question's comments, you can disable the form itself if you want for example the user be able to switch between forms and view or copy some text.
Form.ShowDialog Method: Shows the form as a modal dialog box.
Here is a definition:
Wikipedia: A modal window creates a mode that disables the main window but keeps it visible, with the modal window as a child window in front of it. Users must interact with the modal window before they can return to the parent application. This avoids interrupting the workflow on the main window. Modal windows are sometimes called heavy windows or modal dialogs because they often display a dialog box.
If you don't want to use a modal form, you can initialize the form2 instance like that:
form2.FormClosed += (_s, _e) => this.Enabled = true;
Thus now you can call:
this.Enabled = false;
form2.Show();
You can also check the ShowInTaskBar property of the form2.
Be careful not to add the lambda event handler several times to the same instance: if form2 is just hidden on close, only one FormClosed += is needed, but is required for every instance of a form you want to manage this way.
If you need to disable only certain controls, use them instead of this:
private void SetControlsEnabled(bool state)
{
myControl1.Enabled = state;
myControl2.Enabled = state;
myPanelHavingSomeControls = state; // this changes all inners too
...
}
form2.FormClosed += (_s, _e) => SetControlsEnabled(true);
SetControlsEnabled(false);
form2.Show();
This is the exact use case for a modal form, which disables the parent form and provides visual clues from the OS to tell the user of that relationship. Something along the lines of this will do:
//Code in the event handler that opens the child form
using (Form2 childForm = new Form2())
{
//Put any initialization code here
childForm.ShowDialog(this);
//Any cleanup or using some return value from the form after it closed
}
PROBLEM SOLVED
SHORT STORY
I want to detect "FormClosing()" event through different forms, ie, when form1 is closed that is instantiated within form2, can form2 detect when user presses exit in form1?
LONG STORY
My team and I are working on a windows form application. Project has two forms: one is the main form page and the other is accessed via this main form. Main form looks like this:
And the second one looks like this:
If you press "Ekle/Sil" buttons within the main form, you are directed to form 2 where you can edit database entries. When you press "Sayfayı Yenile" button in the main form, the content of the text areas are refreshed by re-fetching entries from the database.
My problem is, I want to automatically refresh the main form when the user closes the second form. My research suggests I should use an "FormClosing()" event to detect a closing form. However, I want to detect this from the main form. Instantiating main form in second form's source code doesn't seem to be a reliable solution. Anyone can tell me how to do this?
EDIT
I solved the problem:
1) Created a public method within the main form that refreshes the page.
2) Send "this" property from the main form when creating the second form.
3) Added an "FormClosed()" handler within the second form that invokes this public method.
Still, I'm looking for a better solution.
EDIT 2
Better solution InBetween's answer
Simply use the Form.Closed event of the new child windows form. Everything is handled from the main form:
void EkleSil_Clicked(object sender, EventArgs e) //or whatever method is called when button is clicked
{
var newChildForm = new ChildForm();
newChildForm.Closed += childFormClosed;
newChildForm.Show();
}
void childFormClosed(object sender, EventArgs e)
{
((Form)sender).Closed -=childFormClosed;
updateShownData();
}
You can create a event in the second form and raise it when the form is closing .
Handle the event in the main form and refresh the main form when the event is raised
Another option would be to pass Form1 as an argument to Form2. Then use the Form.Closing event in Form2 and use the Form1 reference to trigger something.
Form1 form1Ref;
public Form2(Form1 mainform)
{
form1Ref = mainform;
}
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
form1Ref.SomeMethod();
}
I have a windows form app. The main form has a textbox, and a button to launch another form. When the other form is launched, both forms are on screen (but the launched form is modal). The child form has a textbox and button, and when the button is pressed, I want the textbox on the main form (the parent) to be updated with the value in the textbox on the child form.
How is this functionality achieved?
Ideally you want to keep both forms from being dependent on each other, this could be achieved with interfaces:
public interface IMainView
{
public void UpdateValue(string val);
}
public interface IChildView
{
public void Show(IMainView parent);
}
have your main form implement IMainView and the child implement IChildView, the parent calls child.show(this) and the child calls parent.UpdateValue(blah);
Hope this helps.
If the child form is closed when the button is clicked, you could put a public property which wraps the value of the textbox on the child form. Then the main form can read this property after calling ShowDialog.
If you want this to happen without closing the child form, you can create a function on the main form to change the textbox. Then the child form would call that function.
The best ways to achive this situation are clockWize's and Hans Passants's advices.
But what about that?
Write a property for your textbox at parent form, like this.
public string TextBoxText
{
get { return txtTextBox.Text;}
set { txtTextBox.Text = value;}
}
When you are opening the child form set the owner.
ChildForm f = new ChildForm();
f.Owner = this;
f.Show();
Create an event handler to child forms button click event.
public Button1_Click(object sender; EventArgs e)
{
ParentForm f = (ParentForm)this.Owner;
f.TextBoxText = txtChildTextBox.Text;
}
i didn't compile code; so may have errors :)
}
When a button is pressed to close the launched form, returning you to the main form- the launched form's text box is still in scope.
Closing a form is merely changing the object's state, not disposing of it. So in the button eventhandler that launches the form from the main form, the next line after launching your modal window, it can access the text from the object it launched as the textbox is a child of that form's object. Unless you're launching your modal window in another thread, which I wouldn't figure you are since it's modal, when it is closed, it should go to the next line in the buttons eventhandler that launched it.
your main form may have code something like this right now (haven't done winforms in a while so bear with me if I miss something):
public void Button1_Click(object sender, ClickEventArgs e)
{
SomeFormIWantToLaunch launchForm = new SomeFormIWantToLaunch();
launchForm.ShowDialog(this);
}
You need to just add after launchForm.ShowDialog(this); something like:
this.SomeTextBox.Text = launchForm.ATextBox.Text;
I have a problem with modality of the forms under C#.NET. Let's say I have main form #0 (see the image below). This form represents main application form, where user can perform various operations. However, from time to time, there is a need to open additional non-modal form to perform additional main application functionality supporting tasks. Let's say this is form #1 in the image. On this #1 form there might be opened few additional modal forms on top of each other (#2 form in the image), and at the end, there is a progress dialog showing a long operation progress and status, which might take from few minutes up to few hours. The problem is that the main form #0 is not responsive until you close all modal forms (#2 in the image). I need that the main form #0 would be operational in this situation. However, if you open a non-modal form in form #2, you can operate with both modal #2 form and newly created non modal form. I need the same behavior between the main form #0 and form #1 with all its child forms. Is it possible? Or am I doing something wrong? Maybe there is some kind of workaround, I really would not like to change all ShowDialog calls to Show...
Image http://img225.imageshack.us/img225/1075/modalnonmodalproblem.png
Modal forms do exactly what "modal" means, they disable all other windows in the app. That's rather important, your program is in a somewhat perilous state. You've got a chunk of code that is waiting for the dialog to close. Really Bad Things could happen if those other windows were not disabled. Like the user could start the modal dialog again, now your code is nested twice. Or she could close the owner window of the dialog, now it suddenly disappears.
These are the exact kind of problems you'd run into if you call Application.DoEvents() inside a loop. Which is one way to get a form to behave modal without disabling other windows. For example:
Form2 mDialog;
private void button1_Click(object sender, EventArgs e) {
mDialog = new Form2();
mDialog.FormClosed += (o, ea) => mDialog = null;
mDialog.Show(this);
while (mDialog != null) Application.DoEvents();
}
This is dangerous.
It is certainly best to use modal forms the way they were designed to stay out of trouble. If you don't want a modal form then simply don't make it modal, use the Show() method. Subscribe to its FormClosing event to know that it is about to close:
private void button1_Click(object sender, EventArgs e) {
var frm = new Form2();
frm.FormClosing += new FormClosingEventHandler(frm_FormClosing);
frm.Show();
}
void frm_FormClosing(object sender, FormClosingEventArgs e) {
var frm = sender as Form2;
// Do something with <frm>
//...
}
The first thing that comes to mind would be something like this. You could disable form 1 when you launch form 2 and then have form 1 handle the closed event of the second form to re-enable itself. You would NOT open modal 2 using show dialog.
Now keep in mind, from a user perspective this is going to be quite cumbersome, you might look at doing a MDI application to get all windows inside of a single container.
Your main form will not be responsive until any modal dialogs that are in the same process space are closed. There is not work around for that.
It looks to me like you could use an MDI application setting the Form #0 IsMdiContainer property to true.
Then, you could do something alike:
public partial class Form0 {
public Form0 {
InitializeComponent();
this.IsMdiContainer = true; // This will allow the Form #0 to be responsive while other forms are opened.
}
private void button1_Click(object sender, EventArgs e) {
Form1 newForm1 = new Form1();
newForm1.Parent = this;
newForm1.Show();
}
}
Using the ShowDialog() as you stated in your question will make all of the forms Modal = true.
By definition, a modal form is:
When a form is displayed modally, no input (keyboard or mouse click) can occur except to objects on the modal form. The program must hide or close a modal form (usually in response to some user action) before input to another form can occur. Forms that are displayed modally are typically used as dialog boxes in an application.
You can use this property [(Modal)] to determine whether a form that you have obtained from a method or property has been displayed modally.
So, a modal form shall be used only when you require immediate assistance/interaction from the user. Using modal forms otherwise makes believe that you're perhaps running into a wrong direction.
If you do not want your main form to be an MDI container, then perhaps using multithreading is one solution through a simple BackgroundWorker class is the key to what you want to achieve. Thus, it looks to me like a design smell...
What is it you want to do, apart of making your main form responsive, etc.
What is it you have to do?
Explaining what you have to do, we might be able to guide you altogether into the right, or at least perhaps better, direction.
Actually the answer is very simple. Try
newForm.showDialog();
This will open a new form, while the parent one is inaccessible.