I have a C# Windows Forms application which has a main form that opens two other forms in it's constructor. I'll call them side-panels.
The main form has the GotFocus event handled, which calls Form.BringToFront() for both the side-panel forms.
When this functionality is enabled(i.e. GotFocus is handled), the close button for the main form stops working.
How can I check if the close button was pressed in the event handler?
public Canvas()
{
InitializeComponent();
this.GotFocus += new EventHandler(WindowGotFocus);
tool.Show();
pp.Show();
}
public void WindowGotFocus(object sender, EventArgs e)
{
tool.BringToFront();
pp.BringToFront();
}
When I press the close button the main form, it gets focus, the WindowGotFocus method is called, and application does not close. If I comment 'this.GotFocus += new EventHandler(WindowGotFocus);' in the constructor, it works.
I need this functionality so that the side-panels are shown again if the use switches back to the application from another application.
Well, of course it doesn't work. You caused the form to lose focus, which means that the click never happened as far as the window is concerned.
The proper way to handle this is by simply making the tool windows children of the main window:
var parent = new Form();
var child = new Form();
parent.AddOwnedForm(child);
parent.Show();
child.Show();
This will automatically handle the behaviour you expect - after all, you expect that behaviour because other applications do the exact same thing :) Apart from making sure the child windows show when the main window does, it also closes all child windows when the parent window is closed, among other things.
Related
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 another issue in converting my Winforms program to a WPF program. In my first program, I had a smaller window open to allow the user to adjust some data, and then when it closed, the other form was activated again with the new data.
I used form2.ShowDialog(); to open the form, which automatically makes the parent form deactivated in Winforms. This way when I closed form2, the parent form was activated, and I was able to use an event handler form1_Activated to reload and re-initialize some of the settings successfully.
However, now when I attempt to do the same thing with WPF, I am still able to open form2 using form2.ShowDialog();, but then when I close the form, it does not register the form1_Activated event handler. Instead, in order to reload the settings, I must click on another window, and then come back into my program to register the form1_Activated event handler.
Am I just doing something wrong, or is there another event handler that I should be using in WPF to achieve the same thing I was able to do in Winforms?
Calling ShowDialog() causes the dialog box top appear in modal mode so I don't understand why you would need an event handler to process the results after the dialog box is closed. Keep in mind that you can access public variables in the DialogBox, as well. If I understand your question, this should do what you are asking:
MainWindow:
My_DialogBox dlg = new My_DialogBox();
dlg.Owner = this;
dlg.MyPublicVariable = ''; //some value that you might need to pass to the dialog
dlg.ShowDialog(); //exection of MainWindow is suspended until dialog box is closed
if (dlg.DialogResult == true)
{
//dlg.MyPublicVariable is still accessible
//call whatever routines you need in order to refresh the main form's data
}
DialogBox:
private void OK_Button_Click(object sender, RoutedEventArgs e)
{
MyPublic variable = something; //accessible after the dialog has closed.
this.DialogResult = true;
}
private void Cancel_Button_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}
The MSDN write-up on dialog boxes is pretty good. There may be some tips that might help you even more:
http://msdn.microsoft.com/en-us/library/aa969773.aspx
Good luck!
I'm using c# to make a mobile 6 application. I created another windows form in the project. This is the form that I would like to load first. This is what have tried:
MainMenu gameMenu = new MainMenu();
private void MainForm_Load(object sender, EventArgs e)
{
this.Hide();
gameMenu.ShowDialog();
.....
}
When I run this the emulator comes up but it just stays as the default windows screen. And I don't get any of my forms.
GameMenu's parent is MainForm, which is now hidden, so the Dialog isn't going to be visible. You need to adjust your logic to do one of the following:
show the GameMenu first (i.e. Application.Run(new GameMenu))
Don't hide MainForm
Use gameMenu.Show() instead of ShowDialog()
You may need to get rid of this.Hide() or use gameMenu.Show() instead of gameMenu.ShowDialog() or you may need to do both.
If you have to use gameMenu.Show() instead of gameMenu.ShowDialog(), you may also want to do the following:
Subscribe to MainForm's GotFocus event and call gameMenu.Show() again whenever the other form gains focus unintentionally. Set MainForm's Enabled property to false while the gameMenu is shown if you want to prevent any accidental interaction with the MainForm while the gameMenu is supposed to be shown.
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.