i am trying to implement a UI whereby the parent form loads a child form through showDialog(). the child form would be closed whenever i click anywhere outside the child form, but inside the parent form. clicking anywhere outside the parent form would only cause a normal "alt-tab" action. how do i do this?
If you don't have any controls in the form (if you're viewing a picture for example). Then you can just capture the mouse:
protected override void OnLoad( EventArgs e )
{
base.OnLoad( e );
this.Capture = true;
}
And after that, you just check in OnMouseDown if the click is outside your form.
Othewise, this code could be used:
protected override void WndProc(ref Message m)
{
if ( m.Msg==0x86 && (int)m.WParam==0 )
if ( this.DialogResult==DialogResult.None )
this.DialogResult = DialogResult.OK;
base.WndProc (ref m);
}
It worked great in Windows XP, but in Windows 7 it sounds a beep too, and I haven't investigated why.
I needed the same behavior.
When my application starts, an advertising form is shown and has to be closed whenever the user click on the main form.
Based on the WM_SETCURSOR message, here my solution (to put in the main form) :
protected override void WndProc(ref Message m)
{
var vanishingDialog = ActiveForm as IVanishingDialog;
//0x0201FFFE is for : 0201 (left button down) and FFFE (HTERROR).
if ((m.Msg == 0x20) && (m.LParam.ToInt32() == 0x0201FFFE) && (vanishingDialog != null))
{
vanishingDialog.Vanish();
}
else
{
base.WndProc(ref m);
}
}
And my Advertising dialog (or whatever you want to see disappear on a click to the main form) will implement this interface :
public interface IVanishingDialog
{
/// <summary>
/// Closes the dialog box.
/// </summary>
void Vanish();
}
Work like a charm on seven (no beep).
I just need to improve it in one way :
When the user click on a button in the main form, the advertising form close but the button is not pressed.
I have to transform and send a new message.
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 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 question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Click lost on focusing form
If a form with a MenuStrip is not the window that has focus and you click on the MenuStrip, it uses that first click to make the window active, and then you have to click the MenuStrip again to get the menu to drop down. Buttons work differently. If a form with a button is not active/does not have focus and you click that button, it will register as a button click on that first click, as well as simultaneously making that form active/focused. I really need that menu on the MenuStrip to drop down on that first click, even if the form isn't active.
I tried using the OnMouseClick(...) method to fire a simulated mouse click when the form Enter and/or Activate events are triggered but that doesn't work. The Enter and Activate events are triggered on Mouse Down, so by putting an OnMouseClick(...) call in the Enter or Activate event handler, it's trying to fire a SECOND mouse click before the first mouse click has been released.
I somehow need the OnMouseClick(...) to occur after the Activate event occurs and then after MouseUp occurs.
Use this MenuStrip derivate as replacement:
public class ActivatingMenuStrip : MenuStrip
{
public ActivatingMenuStrip()
{
InitializeComponent();
}
int WM_MOUSEACTIVATE = 0x21;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOUSEACTIVATE)
{
this.Parent.Focus();
}
base.WndProc(ref m);
}
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
}
I'd like a context menu on the caption bar right click
any tips/samples pref in c# ?
UPDATE - for various reasons, right click on the form won't work because the form is not empty and the form is composited dynamically so....
You can do this by trapping the WM_NCRBUTTONDOWN notification that Windows sends when the user right-clicks the title bar. The control class does not have an event for it, you'll need to override WndProc(). Here's an example form, you'll need to add a ContextMenuStrip:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected void OnTitlebarClick(Point pos) {
contextMenuStrip1.Show(pos);
}
protected override void WndProc(ref Message m) {
const int WM_NCRBUTTONDOWN = 0xa4;
if (m.Msg == WM_NCRBUTTONDOWN) {
var pos = new Point(m.LParam.ToInt32());
OnTitlebarClick(pos);
return;
}
base.WndProc(ref m);
}
}
MSDN explains how to handle right-clicks on Windows Forms controls. Controls, including Forms, inherit the MouseClick event.
MouseEventArgs will tell you what button was clicked through the Button property. Have a look at the MouseButtons Enumeration.
if you handle the form mouse-click, you can then use the following code:
private void Dialog_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
this.Text = "new caption text";
}
}
But you'll have to make sure that you generate this event for the top-level control on a form. For instance if you have a group box on the form, it will receive the mouse-click events rather than the form itself, for the areas of the form that are under the group box.
There is already a menu managed by Windows when you right-click the titlebar.
Do you want to replace it completely?
If you want to add to it you will have to use the Win32 API and interop and you will have to subclass the form.
See the AppendMenu() function.
Basically you need to use p-invoke to do this. There is a really great example at Here
You can see from the example you will need to manually mimic the event handlers, but this is pretty straight forward.
You can override WndProc of the form and capture the WM_NCRBUTTONDOWN message:
protected override void WndProc(ref Message m)
{
const int WM_NCRBUTTONDOWN = 0xA4;
if (m.Msg == WM_NCRBUTTONDOWN)
{
MessageBox.Show("Caption right clicked!");
}
else
{
base.WndProc(ref m);
}
}
This code will suppress the window's context menu, however. You may not wish this. The WM_NCRBUTTONDOWN message will also be sent if you right click the window borders as well. You may not desire this either.
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();
}