I have a application that opens some child windows with the parameterless Show()-Methode. So the child-windows have no owner, which enabled them to be behind or in front of the main window.
Now I would like to know if the whole application gets or losts focus. Is there a single event to do this?
I tried OnActivate/OnDeactivate and OnGotFocus/OnLostFocus which only reports events for a single form. This means the OnLostFocus-event is fired when the application lost focus, but also if another form is focused.
You can handle WM_ACTIVATEAPP in your main form and get notified about activation or deactivation of your app:
private const int WM_ACTIVATEAPP = 0x1C;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_ACTIVATEAPP)
{
if (m.WParam == IntPtr.Zero)
BeginInvoke(new Action(() => { Text = "Deactivated"; }));
else
BeginInvoke(new Action(() => { Text = "Activated"; }));
}
base.WndProc(ref m);
}
Note: As it's already mentioned in the comments by Hans, when using above option, you should be careful to not fall into a deadlock and infinite loop. Make sure you read the comments.
As another option, you also can detect activation or deactivation of every form by handling Activate and Deactivate event. When a form deactivates, you can check if the app is still foreground, by checking check if Form.ActiveForm has value:
private void f_Deactivate(object sender, EventArgs e)
{
BeginInvoke(new Action(() =>
{
if (Form.ActiveForm == null)
Text = "App Deactivated"; //App deactivated
else
Text = "Still Active"; //App is still active
}));
}
Related
Is there any possibility to handle an event on a disabled WPF window? The main window is disabled by .ShowDialog() from other windows. In my application there is only one window enabled at a time and I want to improve the usability. If the user clicks on the wrong (disabled) main window the application should auto focus to the enabled window.
I know that disabled means that the window does not respond to any event, but is there a solution like a global event handler or some special WPF event?
I tried a PreviewMouseLeftButtonDown event but that did not work.
// event called from some special/ global event on disabled window
private void Window_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if(App.Current.Windows.Count > 1)
{
foreach(Window w in App.Current.Windows)
{
if(w.IsEnabled)
{
w.Focus();
break;
}
}
}
}
Thanks for your ideas/solutions!
Calling ShowDialog means you want to make window being showed modal, which disables other windows.
Switch this method to Show and you'll be able to use other windows as well.
Refer to this.
Thanks for the hint but as a requirement I've to ensure that the main window is freezed when another window is opened and I've found a solution: Instead of freezing the window with .ShowDialog() I've freezed all controls when a new window is opened with .Show().
private void DisableAllControls()
{
// parallel execution cause of many elements
Parallel.For(0, VisualTreeHelper.GetChildrenCount(this), index =>
{
(VisualTreeHelper.GetChild(this, index)
as UIElement).IsEnabled = false;
});
}
I also added a MouseDownEvent to get focus an the new window if the user clicks on the "freezed" main window. (There will be only one additional window open at the same time).
private void FocusLastOpen_MouseDown(object sender, MouseEventArgs e)
{
if (App.Current.Windows.Count > 1)
{
foreach (Window w in App.Current.Windows)
{
if (w.IsEnabled && w.GetType() != typeof(MainWindow))
{
w.Focus();
}
}
}
}
To reactivate the elements of the main window when the other window has closed I've written a static method which will be executed on the ClosingEvent.
public static void EnableAllControls()
{
MainWindow obj = null;
foreach(Window w in App.Current.Windows)
{
if(w.GetType() == typeof(MainWindow))
{
obj = w as MainWindow;
break;
}
}
if(obj == null) return;
Parallel.For(0, VisualTreeHelper.GetChildrenCount(obj), index =>
{
(VisualTreeHelper.GetChild(obj, index)
as UIElement).IsEnabled = true;
});
}
I am using this code to check if the form is minimized:
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_SYSCOMMAND:
int command = m.WParam.ToInt32() & 0xfff0;
if (command == SC_MINIMIZE)
MessageBox.Show("Minimized");
Variaveis.telaMinimizada = true;
else
Variaveis.telaMinimizada = false;
MessageBox.Show("Maximized");
break;
}
base.WndProc(ref m);
}
This code works like a charm. When I click on minimize button, appear the message "minimized", and when I reopen the application, appear the message "maximized"
But there is a problem. Not always people minimize the form by clicking on minimize button. I mean, if I click on screen OUT the form, the form will also minimize, and when this happens, the code I have do not detect that the form got minimized.
How can I check if the form is minimized (or is invisible on screen) when the form gets minimized after clicking OUT the form?
Ideas? Thanks!
Edit: I already tried doing what is recommended on this post, but do not work:
How to detect when a windows form is being minimized?
this might work for you
//we create a variable to store our window's last state
FormWindowState lastState;
public Form2()
{
InitializeComponent();
//then we create an event for form size changed
//i did use lambda for creating event but you can use ordinary way.
this.SizeChanged += (s, e) =>
{
//when window size changed we check if current state
//is not the same with the previous
if (WindowState != lastState)
{
//i did use switch to show all
//but you can use if to get only minimized status
switch (WindowState)
{
case FormWindowState.Normal:
MessageBox.Show("normal");
break;
case FormWindowState.Minimized:
MessageBox.Show("min");
break;
case FormWindowState.Maximized:
MessageBox.Show("max");
break;
default:
break;
}
//and at the and of the event we store last window state in our
//variable so we get single message when state changed.
lastState = WindowState;
}
};
}
Edit:
and to check if form is not on top anymore you can override OnLostFocus like so
protected override void OnLostFocus(EventArgs e)
{
MessageBox.Show("form not on top anymore");
base.OnLostFocus(e);
this.Focus();
}
I have a Leave Event for a TextEditor in which I perform a validation that an entry is required and display an error message.
Before I perform the validation, I check if the form is disposing, or the Cancel button was clicked. In that case I exit the leave event.
But if the user clicks the X button, these two checks do not capture that and the error message is displayed. I do not want the error message to display if the user clicks the X button. How can I achieve that?
private void TitleTextEditor_Leave(object sender, EventArgs e)
{
UltraTextEditor _currentControl = sender as UltraTextEditor;
if (this.CancelUButton.Focused || this.Disposing)
{
return;
}
if (_currentControl.Text.IsNullOrStringEmpty())
{
MessageBox.Show("Title is required.");
}
}
This is a cruddy problem if you want to suppress the validation error message you display. The only decent way to get ahead of it is by detecting the WM_CLOSE message before the Winforms code sees it and generates the Validating event on the control with the focus.
Paste this code to solve your problem:
protected override void WndProc(ref Message m) {
// Prevent validation on close:
if (m.Msg == 0x10) this.AutoValidate = AutoValidate.Disable;
base.WndProc(ref m);
}
Do consider that you are yelling too loud. The ErrorProvider component is a very decent way to display validation errors and be subtle about it. And nothing drastic goes wrong when the form validates itself on closure, you only have to do this:
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
e.Cancel = false;
}
In the FormClosingEventArgs you have a CloseReason property, you can probably use it.
How to find out if a control's Form has closed or not. I have listened to the VisibleChanged event in order to divine the Form because ParentChanged can happen before the control is added to a Form (e.g. if it is in a Panel). You might also want to unsubscribe from VisibleChanged events after the first one.
//put this at class level
bool _parentClosed;
//put this in controls constructor
//when control first becomes visible
this.VisibleChanged += (s1, a1) =>
{
//find parent Form (not the same as Parent)
Form form = this.FindForm();
//If we are on a Form
if (form != null)
//subscribe to it's closing event
form.Closing += (s2, a2) => { _parentClosed = true; };
else
throw new Exception("How did we become visible without being on a Form?");
};
This is a C# app that sits in the tray as a notifyicon and does its stuff until someone right clicks it and selects close (menu option) or it gets a wm_close from an external app or by the operating system say during a reboot.
protected override void WndProc(ref Message m)
{
case Win32.WmClose:
//recvd message to shutdown
Program.Log.InfoFormat("Shutdown received at {0}", DateTime.Now);
CleanUp();
this.Close(); //this is the main form
break;
//other case statements here
}
//somewhere else on menu exit of notify icon
private void toolStripMenuItemExit_Click(object sender, EventArgs e)
{
Program.Log.InfoFormat("Manual EXIT at {0}", DateTime.Now);
CleanUp();
this.Close(); //this is the main form
}
The this.close() triggers another WM_CLOSE sending the app in a tailspin. What is the correct way to handle this situation ? thank you
Handle form Closing event. and whenever you want to exit just call Close();, and make any other operation rely on closing inside the closing event instead of handling it at WndProc and toolStripMenuItemExit_Click, so:
private void OnFormCloseing(object sender, FormClosingEventArgs e)
{
string reason = string.Empty;
switch (e.CloseReason)
{
case CloseReason.UserClosing:
reason = "Manual EXIT";
break;
case CloseReason.WindowsShutDown:
reason = "Shutdown received";
break;
}
Program.Log.InfoFormat(reason + " at {0}", DateTime.Now);
CleanUp();
}
private void toolStripMenuItemExit_Click(object sender, EventArgs e)
{
this.Close(); //this is the main form
}
More members of CloseReason here.
Remove the CleanUp() call from both toolStripMenuItemExit_Click and WndProc.
Add a FormClosing() event handler in the main window form (assuming you have one). Again, assuming you have a main form window, why do you have a WndProc at all?
The CleanUp() will only be done once, but you will still have two log messages, though both are accurate.
I'm using Microsoft Visual C# 2008 Express.
In my main form, there's that X button to close the form at the top right. How do I add code to this button? In my menu, I have an "Exit" item and it has code that cleans up and closes my databases. How do I add the same code to this button if the user chooses that as a way to exit?
Thanks!
-Adeena
Using the FormClosing Event should catch any way of closing the form.
In the Design view for your form, within the Properties window, select the Events button and scroll down to the "FormClosed" and "FormClosing" events.
FormClosed is called after the form is closed.
FormClosing is called before the form is closed and also allows you to cancel the close, keeping the form open:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
}
If you want to ask the user "Are you sure you want do close this form?", then use FormClosing, where you can set Cancel = True and the form would remain open.
If you want to close some resource only when the form is definitely closed, then you use FormClosed event.
If you are in control of the whole code, then it kind of does not matter. But what you do not want to happen is to clean-up the resources using FormClosing when the the other handler of the event will keep the form open.
FormClosing/FormClosed lets you watch the event for that form which may coincide with the application exiting. However, there is another event you can wire up called Application.ApplicationExit.
In your Main method:
Application.ApplicationExit += Application_ApplicationExit;
...
private static void Application_ApplicationExit(object sender, EventArgs e) {
// do stuff when the application is truly exiting, regardless of the reason
}
Use the Closed-Event of your winform.
This code will capture the user clicking on the 'X' or using Alt-F4 on a form to allow you to do something. I had to use this because the I needed the action to call my closing event, and it wouldn't call it when using the FormClosing Event due to racing events.
/// <summary>
/// This code captures the 'Alt-F4' and the click to the 'X' on the ControlBox
/// and forces it to call MyClose() instead of Application.Exit() as it would have.
/// This fixes issues where the threads will stay alive after the application exits.
/// </summary>
public const int SC_CLOSE = 0xF060;
public const int WM_SYSCOMMAND = 0x0112;
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == WM_SYSCOMMAND && (int)m.WParam == SC_CLOSE)
MyClose();
base.WndProc(ref m);
}
double click the exit button in form'design then
simply call the Dispose() method
Form action method
//
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
if (e.CloseReason == CloseReason.WindowsShutDown) return;
switch (MessageBox.Show(this, "Are you sure you want to exit?", "Exit", MessageBoxButtons.YesNo))
{
case DialogResult.No:
e.Cancel = true;
break;
default:
break;
}
}
You can use form closing events choose or set closing event in properties window
You can add dialog conditions based on what task you want to perform before closing form
private void Form1_FormClosing(object sender,FormClosingEventArgs e)
{
Application.Exit();
//you can also use Application.ExitThread();
}