When the user clicks the x to close the application window I want to pop up a message saying "Shutting Down, please wait" and greyout or disable the rest of the window controls.
This is because my application shutdown and cleanup takes a little while, about 20 seconds.
However, wpf commands in the Window_Closing event handler never seem to do anything. I have a tranparent grey-filled border which overlays the window controls and I want to change the visibility from collapsed to visible. The code is called but nothing changes.
It is as if the request is queued but is not called because the window is closing.
Is there some way to flush this request out?
Edit:
Try this code:
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
_DisableBorder.Visibility = System.Windows.Visibility.Visible;
Thread.Sleep(2000);
}
The app will close after 2 sec, but the border will never show. If you add e.Cancel = true, then the border will show after 2 sec.
You should make a trick.
Within the "Closing" handler, you should cancel the closing, then show the popup (as modeless window), then disable everything on the main window. When the process is over, you can close both the popup and the main windows programmatically.
I'd not perform anything time-consuming within the closing handler.
Hope it helps.
Cheers
Calling DoEvents from System.Windows.Forms.Application seems to do the trick..
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
_DisableBorder.Visibility = System.Windows.Visibility.Visible;
System.Windows.Forms.Application.DoEvents();
Thread.Sleep(2000);
}
Related
I have an application, ParentApp, which launches another application, ChildApp.
ParentApp displays a form while the ChildApp is running - just a kind of Childapp is currently running display with a Cancel button which kills ChildApp.
I want ParentApp to be unusable while ChildApp is running, so whenever someone clicks on ParentApp I want to bring the ChildApp to the foreground, which is fine.
So I've added this event handler to the ParentApp which responds to the Activated event of the form.
private void ParentAppForm_Activated(object sender, EventArgs e)
{
IntPtr childHwnd = _childApp.MainWindowHandle;
SetForegroundWindow(childHwnd );
}
(GotFocus didn't seem to work)
Unfortunately, if the user clicks the Cancel button on the ParentAppForm, the event handler for that button is never hit, because the Activated event fires first and sets the foreground window to another process.
Is there around this - to allow the button event to fire even though the application is not in the foreground?
As a quick workaround, you could check whether the mouse pointer in inside the area described by the Button.Bounds when the Form is activated.
You can translate the mouse pointer position to the Form.Bounds coordinates using PointToClient with the Cursor.Position coordinates.
Something like this:
private void ParentAppForm_Activated(object sender, EventArgs e)
{
if (this.button1.Bounds.Contains(this.PointToClient(Cursor.Position)))
ChildForm.Close(); //Or ChildApp.Kill()
else
ChildForm.BringToFront(); //Or SetForegroundWindow(ChildApp.Handle)
}
We have some Forms that have no border / no toolbox (overlays)
Whenever the user clicks somewhere else in the underlaying window, the overlay-form is send to the background (regular non-modal-form behaviour)
Is there an Event for this, so the "overlay" could detect it's visibility change and close itself?
Maybe it can be handled within in resize / paint event, where the "invisibility" can be catched?
Background:
Typical "Select-Or-Create-New" UseCase. Clicking "plus" shows the tiny creation-form. Currently it's "topmost", so the user needs to hit "Escape" to get rid of it. (Else there would be a mess of "background-overlays", hence the question)
Would be more "userfriendly" if a click on something else closes that "tiny form":
You can use the Deactivate event of the form:
private void Form1_Deactivate(object sender, EventArgs e)
{
Visible = false;
}
I am trying to create a windows form that gets displayed for 2 seconds when triggerd by an event, and then closes automatically.
I have tried several options. This is my current code:
this.aletPopup.StartPosition = FormStartPosition.CenterScreen;
this.aletPopup.Show();
Thread.Sleep(2000);
this.aletPopup.Close();
This preforms the actions that I desire, however, when the form loads it does not load the label or image which is on the form. Instead, the area where the image and label are become transparent. My desired output is this:
I have also tried using this.aletPopup.ShowDialog();, which does display the graphics. However, the form will not close automatically when using this method.
EDIT: I am attempting to use
Michael Perrenoud's solution. However, I cannot get the form to close. I have a timer set at a 2000ms interval which is initally disabled. Am I overriding the OnShown correctly?
public AlertPopForm()
{
InitializeComponent();
}
private void closingTimer_Tick(object sender, EventArgs e)
{
closingTimer.Enabled = false;
this.Close();
}
private void AlertPopForm_OnShown(object sender, System.EventArgs e)
{
closingTimer.Enabled = true;
closingTimer.Start();
}
Instead, how about leveraging ShowDialog, and then using a Timer on the dialog form. In the Tick event of the Timer, close the form.
this.aletPopup.StartPosition = FormStartPosition.CenterScreen;
this.aletPopup.ShowDialog();
You could even pass the interval into the .ctor of the dialog form if you wanted some flexibility.
It's very important to note here that you'd need to leverage the OnShown override to actually Start the Timer so the form is in fact shown to the user.
The reason can be in Message Loop. When you block your thread by Thread.Sleep, it also blocks Message loop.
You can make like this:
this.aletPopup.StartPosition = FormStartPosition.CenterScreen;
this.aletPopup.Show();
for(var i = 0; i<= 200; i++)
{
Thread.Sleep(10);
Application.DoEvents();
}
this.aletPopup.Close();
DoEvents will process messages from message queue during that time.
When calling Thread.Sleep you're blocking the UI thread, thus preventing it from processing UI events.
You need to ensure that Close is called after 2 seconds without actually blocking the main thread. There are a number of ways of doing this, such as using a Timer, or something like Task.Delay:
aletPopup.StartPosition = FormStartPosition.CenterScreen;
aletPopup.Show();
Task.Delay(TimeSpan.FromSeconds(2))
.ContinueWith(t => aletPopup.Close(),
TaskScheduler.FromCurrentSynchronizationContext());
The reason this is happening, is that you are halting the thread that draws the form. So the form has time to display, but as it's being drawn, the thread is being stopped.
Easy enough to fix....
Add an event handler to the popup for the Load event with the following handler:
private async void handleLoad(Object sender, EventArgs args)
{
await Task.Delay(2000);
Close();
}
Remark
Because you used Show(), the user could always click around this popup. If this is undesirable, then use ShowDialog() instead.
Did you try a refresh to redraw the form?
this.aletPopup.StartPosition = FormStartPosition.CenterScreen;
this.aletPopup.Show();
this.alertPopup.Refresh();
Thread.Sleep(2000);
this.aletPopup.Close();
I have a C# GUI app that shows a message using MessageBox.Show(Message);, however if the user fails to click on this, and then requests shutting down the PC, it blocks the shutdown.
How do I prevent my open dialog box from blocking the shutdown?
I'm assuming you're using WinForms since you didn't mention WPF. You can't use a MessageBox if you want to control closing behavior. You'll have to build your own screen to act as a message box and use the ShowDialog method to display it. Your screen can handle the FormClosing event to detect when Windows is shutting down:
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.WindowsShutDown)
{
//...
}
}
So you'll want to allow the screen to close in this case and perhaps take other action for other types of close signals. To prevent the screen from closing, set the Cancel flag on the FormClosingEventArgs parameter to true;
I have a WPF window that is run on a background thread as a sort of "notifier window"... when an event is raised, it displays a message... a user clicks the "Snooze" button and I call this.Visibility = Visibility.Collapsed
The very moment that I hide the window (either by calling this.Hide() or setting the Visibility as mentioned above)... the "ShowDialog()" code releases the window and closes it.
This is absolutely a bug in the WPF code (which I've identified via reflector)... but my question remains. Has anyone been able to come up with a work-around for this issue?
I've tried many things and am now reaching out to ya'll smart people :)
You can't hide a modal dialog. That's like asking, "How do I get to 100mph in reverse?" You don't, you drive the car forwards.
Use Show, not ShowDialog. Alternately you can simply re-ShowDialog when it needs to become visible again.
Timothy's Answer is good. I just needed for my scenerio to add the following
window.Closed += new EventHandler(window_Closed);
window.Show();
System.Windows.Threading.Dispatcher.Run();
and then in the event...
void window_Closed(object sender, EventArgs e)
{
System.Windows.Threading.Dispatcher.ExitAllFrames();
}
I needed to do this because it was hanging on the Run after the form was really closed.
In order to show modal window always use ShowDialog().
Use Close() instead of Hide().
Handle the FormClosing event like that:
private void OnFormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
this.Visible = false;
}
OK, and as quickly as that - my boss (old C++ goofy guy that he is) figured out the answer.
Here was the code inside of my background thread (which is set to STA mode):
// Show dialog - keeps the thread open and shows the window! Yay!!!
new BeamUI.Notifier.NotifierWindow().ShowDialog();
And here is the modification, that strangely enough works perfectly :)
// Show... hmm, that shows the window... but how do I keep this thread open?
new BeamUI.Notifier.NotifierWindow().Show();
// ZOMG - a line of code that JUST keeps the thread (and msgpump) going!!!
System.Windows.Threading.Dispatcher.Run();
And that's it.
This kinda thing makes me hate C++ people though, and makes me want to just say "if you just built it right in the first place I wouldn't have to look for a work-around!" (j/k)