How to know if the dialog box is closed completely? - c#

I have a parent form Form1 which is opened in fullscreen mode. There's a button in Form1 which opens a form Form2 (using .ShowDialog() method). When the form is closed, the program captures the screenshot of the Form1. But in the screenshot I can still see the Form2 which still has some opacity during closing (I'm using Microsoft Windows 7 Pro which animates the closing of the form by reducing the opacity of the form).
So how can I know when the Form2 is 100% closed, so that I can take screen shot of the program?
Edit: I'm using Graphics.CopyFromScreen Method in Form1 to capture the screen shot.
And Form2 is closed by the button click in Form2 using this.Close() method.

If there's a way to know for sure the Windows desktop manager animation has completed, it's not in .NET itself. You'd have to find a native API that provides this detail (and I'm not sure one exists…I'm not aware of one if it does) and execute it via p/invoke.
I think commenter/answerer dotctor has provided a couple of good options: just delay long enough to account for the animation, or shift the offending window out of the way as it's closing (and if you do reuse the same Form2 instance, shift it back before displaying it again).
That said, you might also consider using the Control.DrawToBitmap() method to do the screenshot, since you seem to want the image to be the full-screen image of the Form1 window. It has some limitations (which you can read about in the docs), but as long as none of those apply in your case, it might be a more convenient way to get the image you want.

I came up with an easy solution that contains no waiting.
add an handler to FormClosing event on Form2 and set its location to somewhere off screen.
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
this.Location = new Point(-4000,-4000);
}

Related

C# Parent form open child form, call child function after parent closes

To cut a long story short...
I need Form_1 to open Form_2.
I need Form_2 to execute code, AFTER Form_1 has been hidden.
(without user interation)
At the moment, my Form_1 code is thus....
function myFunction(){
// Create a new instance of the child form class
Form2 F2 = new Form2(this,d);
// Minimise current form
this.Hide();
// Show the child form
F2.Show();
}
F2.Show then initiates further code from Form2_Shown event.
Problem is that I need the Form2_Shown code to run after Form1 has completely hidden.
Because Form1.myFunction calls F2.Show(), then Form2_Shown will allways occur whilst Form1 is not 'retired' completely.
Is there a way to seperate this chain of events to get the desired outcome?
Open Form_2
Close Form_1
Run code in Form_2 with no remaining connections to Form_1 ?
Threads ?? (he says in ignroance of them)
And before you ask ... this is for a screen capture application.
Form_1 is the UI with buttons.
Form_2 is a fullscreen transparent form.
Because Form_1 is hanging in there, it causes black images.
If I use the same model, but trigger the screen capture off of a keypress in Form_2, then everything works perfectly.
Hope that makes sense.
I can of course post reams of code, if required.
Many Thanks.
You could pass in a reference to Form1 in Form2's constructor. Then from the constructor of Form2 call the Form1.Hide() method. Then, from Form2's constructor call the Show() method on Form2.

Form gets disposed on Hide()

I have a C# WinForms application running on .NET Framework 4.0.
When the user is inactive for a certain period of time, I want it to hide all the displayed forms and show an icon in the notification area. When the user clicks that icon, a login form appears and if the credentials are valid, it opens the exact forms that were open before.
To do this, I store the list of open forms in a List of Form objects and hide them, like this. This method is called by a Timer:
private void LogOut()
{
foreach (Form form in Application.OpenForms)
if (form.Visible)
{
GlobalVariables.formList.Add(form);
form.Hide();
}
}
When the credentials are validated, I try to make the forms visible again, like this:
//Show the previous forms.
foreach (Form form in GlobalVariables.formList)
form.Visible = true;
//Clear the forms list.
GlobalVariables.formList.Clear();
If I only have the MainForm open when I hide the forms, it shows it back fine when logging back in. If I have any other forms open (which are opened using ShowDialog() from the MainForm), the program will crash on form.Visible = true; and give me the following error message:
ObjectDisposedException was unhandled
Cannot access a disposed object
How can I fix this problem? An alternative way of doing what I'm trying to achieve would also be great.
Please note that using a try - catch block to determine if the form has been disposed and just relaunch the form is not an option as the user may have unsaved input in the hidden forms.
I couldn't manage to find anything related online in over 3 hours of search so any help would be much appreciated!
EDIT: After trying various things, I have noted that the problem only occurs on forms I have opened forms using ShowDialog(). If I only have forms opened using Show(), everything works fine.
However in my case, using Show() is not an option because I cannot have the user click on things in the parent form. Hiding the parent form is not an option either as he needs to see information in the parent form.
Clearly hiding a form is more impactful than you counted on. Your code was involved in a security review that Microsoft conducted on Winforms. Very thorough, not often visible in the way it behaves but very visible in the source code. One rule is imposes is that a user should never lose control over the application.
A dialog is very troublesome that way. The core problem is that ShowDialog() creates a modal window that disables all the other windows. That creates an opportunity for malware, very easy to take advantage of, all it has to do is hide a dialog and you snookered the user. There isn't any way that the user can gain control of the app again. The one window that was enabled is hidden with no way for the user to re-activate it again. All the other windows are disabled so trying to click on them, or their taskbar button, will not have any effect. All that's left is for the user to use Task Manager to kill the app. And if the user account is locked down then that's not an option either.
I can hear you sputter by now: "But, but, it is my code that hides the dialog, not malware!" That's not the way it works in Windows, there's no way to tell that it actually was your code that did it. Not only because it could be injected code, it doesn't even have to be code that runs in your process. Any code can do it, it is part of the winapi.
So there's a specific counter-measure against this built into Winforms, it will automatically close a form if it is hidden while operating in dialog mode. Which of course has a big impact, code that was written after the ShowDialog() call will now run. Anything is possible, but a sure-fire mishap in your case is that this disposes another window and an attempt to revive it will die.
The rough guidance here is that you are doing it wrong. You are trying to build a security system on top of one that's already highly secure and heavily tested. And it is very risky, handling passwords yourself is a very good way to make the overall system much less secure. The average user will of course favor picking the same password as he used to login to Windows. Makes it much easier for an attacker to harvest that password.
Call LockWorkStation() instead.
After many hours of trial and error, I found out what the problem was.
My understanding of modal forms was that code would continue executing in the parent form only after the modal form was closed. In fact, the specification found on MSDN states:
A modal form or dialog box must be closed or hidden before you can continue working with the rest of the application.
This introduced a subtle bug in the way I handled the forms. This is the code I used to display the forms:
using (var theForm = new CreateInvoice())
{
theForm.ShowDialog();
if (theForm.Updated)
{
GetInvoiceStatus();
}
}
The using statement disposes of theForm as soon as the statement exits. Normally, this works perfectly fine as it would be called only when the user closes theForm. However, because ShowDialog() permits the parent form to continue its work when it is hidden, this meant that the code actually exited the using statement, which effectively disposed of theForm, resulting in my error.
Testing, it seems that Hide()ing a modal dialog - closes it. It actually triggers the FormClosing event.
Tested like this: (Also, see this answer.)
private void button1_Click(object sender, EventArgs e)
{
Form1 f1 = new Form1();
f1.ShowDialog();
}
private void button2_Click(object sender, EventArgs e)
{
Hide();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
MessageBox.Show("Closing");
}
EDIT
I noticed this actually doesn't solve the mystery, just adds more information. Here's another piece of information: When you're setting Visible to true - you're not showing it modal again. This time it's equivalent to Show().
One suggestion to the design: instead of saving forms(views), you should save the data that the form holds(Model) and destroy the form. When you need the form again, create it back with the data(model). First, this can resolve this mysterious dispose problem, second, each form will need GDI resource, which are limited, if two many forms, you'll encounter the memory and GDI problems.
As how to do this, please refer the MVC or MVP design pattern.
BTW my guess on this problem: when you make the form visible, it will try find its parent, but its parent may be already disposed. I encountered this problem once, it throws the object disposed exception.

MDI application issues

General description of application:
Main form as MDI Container. On application start, if there is no xml file for database configuration (it is checked in Main form) Main form i call another form as showdialog() to fill all database info to build connection string. Then i close form and open another for login, then i get back to Main form, which has Split Container (2 panels: 1-menu on top, 2-content from child forms).
I open forms with:
private void PlanButton_Click(object sender, EventArgs e)
{
plan.TopLevel = false;
KontenerMenu.Panel2.Controls.Add(plan);
plan.Dock = DockStyle.Fill;
plan.Show();
}
and close form with:
private void Plan_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = false;
this.Hide();
}
Problems i have with app:
1. When i hit Cancel button when i open ShowDialog() form for database app crashes. Cancel button is simply:
private void cancelButton_Click(object sender, EventArgs e)
{
Application.Exit();
}
2. I have problem with clicking button to open/close/open again child forms. When i hit 'X' and want o open, app crashes with exception that it cannot refer to non-existing object
3. I have several buttons when i hit one and then another one it is always below the first one and not on the top
4. For example my form is 200x200 and in right down corner i have button (so location let's say 190x190) and i hit maximize button. My button is still on 190x190 and i would like to have it on down right corner. I couldn't find any property for that. Is there any or i have to write some code for that.
I'm not sure I understood your questions. Please make them clear.
But as an answer to question #4, there's an anchor property that does what you want.
Instead of trying to exit the application from within the dialog form itself you should return a DialogResult value and test that in the main form. The cancel button on the dialog doesn't need any code, just set its DialogResult property to 'Cancel' and if you have an Ok button set its DialogResult to 'OK'.
DialogForm f = new DialogForm();
DialogResult r = f.ShowDialog();
if (r == DialogResult.Cancel)
{
Close();
}
I can immediately see a number of problems with you code, including:
If you're going to add controls dynamically using Controls.Add, you should make sure the controls you're adding are dynamically created using new(). I get a sense that you don't have a clear understanding of object lifetimes and the WindowForms control life cycle.
The Application.Exit method should be used only in unusual cases. It's purpose is to achieve exactly the result you're observing - to immediately "crash" the application. The easiest way to have a button close a modal dialog is the set the DialogResult property of the button.
Winforms has a very elegant system for placement of control on a variable sized window. In order to use this system, you should familiarize yourself with the Anchor and Dock properties that are available on all controls.
It looks like what you're doing is attempting to learn WinForms by trial and error. You can do this, but it will take much longer and be much more painful that getting a hold of a good tutorial, book, or perhaps even attending a class if you can manage it. That will allow you to take these issues one at a time and have a much more enjoyable learning experience.

How to minimize a winforms app when there is at least one modal window opened

I have two form classes (Form1 and Form2) in a Winforms App.
Form1 is like this:
Form2 is like this (ShowInTaskbar = false):
And this code on Form1:
Form2 someForm = new Form2();
private void btOpenAnotherWindow_Click(object sender, EventArgs e)
{
if (someForm.ShowDialog(this) == DialogResult.OK)
MessageBox.Show("OK!!!");
else
MessageBox.Show("Not OK.");
}
That is, a window with a button which opens modally another windows when clicked, and waits for the user to close the second window (by clicking the "OK" or "Cancel" button). And depending how it was closed, do alternating actions (represented here by the MessageBox.Show() calls).
I need:
The user can use only one window at a time. (Modal forms, That's why I used ShowDialog() instead of Show())
When the form closes, do something depending on how the form was closed (the "if (someForm.ShowDialog(this)...")
To be able (as a user) to minimize the WHOLE APP.
To be able to "unminimize" the app to the former state correctly.
The program to respond to WIN+M (minimize all) keys combination.
the above example fails in two ways:
(need 5) Doesn't respond to WIN+M
(need 3) The app seems to minimize when the Minimize title bar button is clicked, but it is an illusion because the main form (Form1) does not minimize and it is in fact just hidden behind the other opened windows. Only running the example with an empty desktop shows what really happens. Pics follow:
Before Minimize button is clicked:
After:
Note:
The Main form is not minimized
The Form2 is in the left botton corner of the screen.
Form2 is a full blown window (not a dialog window per se) and I need the user to interact with it only until it is closed and I also need the user to be able to miminize the whole app in case he needs it.
It is a shame I can't post here the real forms, It would be clearer than these mock-ups.
I need a solution that works with many levels of modal windows (not only two as this example shows). Any suggestions?
I may need a little more information about what you're trying to do here. I have a simple form (Form1) with a button on it, which calls this code:
private void button1_Click(object sender, EventArgs e)
{
Form1 form2 = new Form1();
form2.ShowDialog();
}
When I click the button, I get a second instance of the same form, but it's modal. I still have the option to minimize this second modal form (I obviously can't interact with the first form), and when I do minimize the second form it does minimize the entire application (both forms). Now obviously you're asking the question, so I don't think I'm understanding you. =) What about this scenario do you wish to change?
C
There is probably some way to hack this functionality using API calls, but I would probably suggest doing some type of overlay with a control inside your main form rather than an actual window. This would allow you to make it "modal" and still have the ability to minimize/resize the main window.

csharp winform modal window, able to click on main window

language c#, winform
how do i create a modal window or such a thing that when it still showing
i would still be able to click or interact with the main window..
thanks.
put some code please or links..
Make the dialog non-modal (use Show instead of ShowDialog), and make it top-most (TopMost = true)
Just use the overload of Form.Show() that takes a form as a parameter, like this:
Form f = new Form();
f.Show(this);
This will keep the form always on top of the form that calls it, but still let you click and access the calling form.
Some confusion here I think;
Modal is when the window blocks the underlying window, and must be closed to enable the underlying window to regain control. Form.ShowDialog(owner) is used to accomplish this.
Non-Modal is a window that is opened "in parallell" to the underlying window. Both windows can be accessed and respond to mouse and key events. Form.Show(owner) to accomplish this.
Modality by definition means that you are not able to click anywhere else. You can create another form and show it with Show() method.
Show() Method allows you to click anywhere while ShowDialog() won't

Categories