I am writing an IM program, and I have the method to make a form flash and stop flashing... question is, how do I implement it?
When a message arrives, I can set the window flashing, but I need to make sure it doesn't have focus. Checking the focued method always seems to return false and so it flashes even when the form is open.
Also, which event to I need to handle to stop it flashing? When the user clicks the form to make it maximise, or switches focus to the form, I need a way of stopping it.
What's the best way?
You can handle the Activated and Deactivate events of your Form, and use them to change a Form-level boolean that will tell your code whether your form has the focus or not, like this:
private bool _IsActivated = false;
private void Form1_Activated(object sender, EventArgs e)
{
_IsActivated = true;
// turn off flashing, if necessary
}
private void Form1_Deactivate(object sender, EventArgs e)
{
_IsActivated = false;
}
When a message arrives, you check _IsActivated to determine if your Form is already the active window, and turn on flashing if it isn't. In the Activated event, you would turn off the flashing if it's on.
The Focused property of your form will always return false if it has any controls on it. This property refers to whether the control in question (the form, in this case) has the focus within your application's form, not whether the application itself has the focus within Windows.
Checking if the form is minimized or not:
if (this.WindowState == FormWindowState.Minimized)
{
MakeFormFlash();
}
else
{
MakeFormStopFlash();
}
Event to trigger when the form is activated by user or code:
this.Activated += new EventHandler(Form_Activated);
Well Focused should be the property to check, so you need to try and work out why that is always returning false.
As for what event to listen to, probably the GotFocus event, though that may not work until you can work out what is wrong with the Focused property.
There are a number of ways you can handle this. Probably the easiest would be to have a flag that you set whenever the form is flashing so this can be reset on re-activation of the form e.g.
Code for base IM window form
private bool IsFlashing;
....
// Code for IM windows
public void OnActivate(EventArgs e)
{
if (IsFlashing)
{
// stop flash
IsFlashing = false;
}
}
public void Flash()
{
// make flash
IsFlashing = true;
}
Then wherever you do your code to handle the new message you would just need to check that the particular conversation window (if you handle multiple ones) that the message is directed at is the current active one:
public void OnNewMessage(AMessage msg)
{
Form convoWindow = FindConvoWindow(msg.Sender);
if (Form.ActiveForm == convoWindow)
{
// update the conversation text
}
else
{
convoWindow.Flash();
}
}
Related
Hey stackoverflow community. I have a question that I've been trying to figure out for several days now and I was hoping for some help and general advice.
I have been developing a small application. The main form has a few controls some of which open dialog boxes: an OpenFileDialog, SaveFileDialog, and then a custom dialog for a specific task. The problem arose in the custom dialog box. The basic functionality in a part of the custom dialog box was the ability to click a button that would allow the user to press a key, that key would then be "read" and input into a variable for later use.
My initial thought was to override WndProc and have a check for a bool in it, if the bool was true, the data from a WM_KEYDOWN message would be stored in a variable and the bool would be set to false. I quickly figured out that doesn't work since Dialog Boxes don't get messages like a normal form does.
My question is what is the best/recommended way to achieve this functionality? I've tried some ad hoc workarounds like just using a regular form and disabling the main form while the second form is active, but that didn't work either and I figured it would be better to ask for advice before I continued.
Any help is greatly appreciated.
Edit
Here is some code to demonstrate my current issue
This has quite a few lines removed since I don't think it would be helpful to post hundreds of lines in here
internal class GUI
{
// This class has all the code for the main form
// this is one of the Event Handlers that calls the second dialog box
private static void addItemAbove_Clicked(object sender, EventArgs e)
{
ActionItemDialog aid = new ActionItemDialog();
if(aid.ShowDialog() == DialogResult.OK)
{
ActionList.Items.Insert(list.SelectedIndex, aid.ActionItem);
}
}
}
internal class ActionItemDialog : Form
{
// This class is a custom dialog box for the user to input some data
private bool keyCaptureOn = false;
// This event handler is attached to a button on the dialog box
private void getKey_Clicked(object sender, EventArgs e)
{
getKey.Text = "Press Any Key";
keyCaptureOn = true;
}
// This is the way I was originally trying to get the keypress
protected override void WndProc(ref Message m)
{
if(m.Msg == 0x100)
{
if(keyCaptureOn)
{
// have never been able to make it in this.
}
}
base.WndProc(ref m);
}
}
Also it is worthy to note, I have already tried what all the other questions about this have recommended. I've tried setting KeyPreview to true. I've also made a regular form and used Form.Show() and had it emulate a Modal Dialog but I was still never able to get into that second if statement.
In your ActionItemDialog form, you can add a filter via IMessageFilter to trap keypresses.
When we want to trap a key, we call filter.trapKey = true;, which will fire off a custom Key() event when the user presses a key.
When the form is dismissed, we remove the filter and event subscription.
Here's an example:
public partial class ActionItemDialog : Form
{
private MyFilter filter;
public ActionItemDialog()
{
InitializeComponent();
this.FormClosing += ActionItemDialog_FormClosing;
filter = new MyFilter();
filter.Key += Filter_Key;
Application.AddMessageFilter(filter);
}
private class MyFilter : IMessageFilter
{
public bool trapKey = false;
public delegate void dlgKey(int key);
public event dlgKey Key;
public bool PreFilterMessage(ref Message m)
{
if (trapKey && m.Msg == 0x100)
{
trapKey = false;
Key?.Invoke((int)m.WParam);
return true;
}
return false;
}
}
private void getKey_Click(object sender, EventArgs e)
{
getKey.Text = "Press Any Key";
filter.trapKey = true;
}
private void Filter_Key(int key)
{
getKey.Text = key.ToString();
}
private void ActionItemDialog_FormClosing(object sender, FormClosingEventArgs e)
{
if (filter != null)
{
Application.RemoveMessageFilter(filter);
filter.Key -= Filter_Key;
filter = null;
}
}
}
Note that the filter will only trap key presses when YOUR app is in focus (any form of your app). So if the user clicked to trap a key press, but then switches to another window before pressing the key, then it will not be captured.
To capture a keystroke when ANY application is in focus, you'd have to wire up a low level keyboard hook via WH_KEYBOARD_LL. This would be overkill since I'd expect the key press to be captured only when that app is in focus. This could be an alternate approach, though, if you need to trap key presses globally, as registering a hotkey fails if another app already took the combo you want.
Is there any way to have a messagebox immediately pop up when a form opens? I just want to display a short message about how to use the form when it opens. I tried
private void myForm_Load(object sender, EventArgs e)
{
DialogResult dialogOpen = MessageBox.Show("Use the navigation menu to get started.", "Welcome!", MessageBoxButtons.OK);
}
but it doesn't work.
Showing a MessageBox during Form_Load works just fine for me. I literally copy/pasted the code from your original post, and it worked. I'm on .NET Framework 4.5 on Windows 8.1.
Are you sure your Load event handler is getting called? Perhaps the it's not hooked up to the Load event properly.
I don't see why it wouldn't work in Form_Load. Definitely try doing as others have pointed out by putting it beneath form initialization.
Though, given that you're just showing a message box, I don't think there is any reason to store the result, so a simple MessageBox.Show(message); Should do the trick.
As #s.m. said, from a UX point of view, having a notification thrown in your face as soon as the app starts would be very obnoxious, at least if you have it EVERY time. Personally, I would create a boolean Settings variable, set it to true the first time the message is displayed, and only display it when the setting is false, i.e. the first time the message is displayed.
private boolean splashShown = Properties.Settings.Default.splashShown;
private void Form_Load(object sender, EventArgs e)
{
if (!splashShown)
{
MessageBox.Show("message");
myForm.Properties.Settings.Default.splashShown = true;
myForm.Properties.Settings.Default.Save();
}
}
And set up the splashShown Setting in your form properties.
If the problem is that your Form_Load() method isn't actually attached to your Form.Load() event, you can double click the form window in the designer and it will automatically created the Form_Load() base method for you and attach it to the Form.Load() event
Is there a reason to use the Load method of the form? If not you could to it in the constructor of form. If you want it to show up immediately after your form loads, you should do it in the constructor after the form is initialized. It should look something like this:
public partial class myForm : Form
{
public myForm()
{
InitializeComponent();
DialogResult dialogOpen = MessageBox.Show("Use the navigation menu to get started.", "Welcome!", MessageBoxButtons.OK);
}
}
The constructor (public myForm()) and the InitializeComponent(); should be automatically added to the form by Visual Studio after creating it.
Form_Load event occurs before the form is really visible.
I use:
static private bool splashShown = false;
private void Form1_Activated(object sender, System.EventArgs e)
{
if (!splashShown)
{
MessageBox.Show("message");
splashShown = true;
}
}
I have used this and it works fine. App start brings up messagebox first before all else.
InitializeComponent();
MessageBox.Show("put your message here");
I have a custom control (custom ComboBox). It`s work well, when I press "arrow button" it deployed, if I press it again it deployed too, but if it are deployed and I press anywhere in my form - it close but then, when I'm trying to open it - I must press "arrow button" two times. So I need to detect this moment, when I click outside of my combobox.
Code to open ComboBox(call in ButtonClick)
private void OpenComboBox()
{
if (drop_flag)
{
...
popup.Show(this);
}
else
{
drop_flag = true;
}
}
And Close event
private void popup_Closed(object sender, ToolStripDropDownClosedEventArgs e)
{
drop_flag = false;
}
So, I want something like this
private ClickedOutsideControl()
{
dropflag = true;
}
Thats not that easy.With basic .net you always need some kind of control / references to intercept clicks by binding click events. For Example if you have an MDI Parent (Mainwindow you can intercept its clicks).
Another way (using windows api) is to hook inso system events See the following stackoverflow post Global mouse event handler.
But you should think twice if you really need this.
In the form, you can pre-process messages sent to controls by using a message filter. Here is my FAILED attempt to implement the desired functionality:
public partial class frmAutoCloseDropDown : Form, IMessageFilter
{
int _lastMsg;
public frmAutoCloseDropDown()
{
InitializeComponent();
Application.AddMessageFilter(this);
}
// THIS ATTEMPT DOES NOT WORK!
public bool PreFilterMessage(ref Message m)
{
const int WM_LBUTTONDOWN = 0x0201;
if (m.Msg!= _lastMsg) {
_lastMsg = m.Msg;
}
if (m.Msg == WM_LBUTTONDOWN) {
// You would have to do this recursively if the combo-boxes were nested inside other controls.
foreach (ComboBox cbo in Controls.OfType<ComboBox>()) {
cbo.DroppedDown = false;
}
}
return false;
}
// Note: Dispose is created inside *.Designer.cs and you have to move it manually to *.cs
protected override void Dispose(bool disposing)
{
if (disposing) {
Application.RemoveMessageFilter(this);
if (components != null) {
components.Dispose();
}
}
base.Dispose(disposing);
}
}
Why does it not work? Probably because the new messages generated by cbo.DroppedDown = false that are sent to the form to close the drop-down are appended to the message queue and are only processed after the left mouse button click has been processed. This means that even when with PreFilterMessage our attempt to close the drop-down comes too late.
A possible solution would be to re-send WM_LBUTTONDOWN to the right ComboBox. You would have to interpret the parameters of the message to get the mouse coordinates and look to which combobox they are pointing to get its HWnd. My attempt to do this also shows that the behavior also depends on the drop-down style. It also has the undesired effect to close the drown-down you just opened. And what happens if you click in the drop-down itself to select an entry?
Probably you could do it, but the code tends to become very complicated. It's not worth the effort.
This is a winform C# question. I have a textbox with a validating event listener to validate the content of the textbox against a regular expression.
After the validation, if entered value is not proper,i am showing the messagebox and i am cancelling the event so that mouse cursor move back to the textbox which has improper value.
This is working fine when i move out from that textbox to other buttons/textboxes.
But when i enter improper value and close the form (with the close button on right top corner), it validates the textbox contents and throws up the messagebox and form doesnot close as i am cacelling the event.
The problem is, when I click the X button on the right top corner of the form, I don't want the validation to be fired because I am closing the form anyway. How can I do this?
I will post the code snippet as soon as possible.
To use validating handlers such as the 'txtIPAddress_Validating()' handler below while being able to close the form without having to enter valid entries to do so, I do the following:
1) Initate validating handlers:
From the control properties of the control you wish to activate validation for, double click the 'Validating' event from this control event list. A control event list is accessed by clicking this control's property sheet’s event (lightning looking) toolbar button. You can then enter the code in the automatically generated handler with a name combining both the name of the control and '_Validating'. The part of this handler where something is established as invalid can force valid entries by adding the 'e.Cancel = true' instruction.
For such validating method examples, See 'txtIPAddress_Validating()' and 'txtMaskBits_Validating()' code below. Do not get distracted by the complete validation mechanism of these specific examples. All you need to see and reproduce in your own code in order to force validation is to add the 'e.Cancel = true' instruction at the right place of your own validating method. That is when the value is identified to be invalid.
At this point the validation should work fine but any attempt to close the form will trigger validation which will stop and insist for valid values before being able to close the form. This is not always what you want. When it is not so, I continue with the following.
2) 'Cancel' button that also cancels (disables) all validations:
a) Place a regular 'Cancel' button on the form which is associated to a method such as the 'btnCancel_Click()' method below.
b) Before the regular 'this.close();' instruction, add the 'AutoValidate = AutoValidate.Disable;' instruction. This instruction disables all 'validating' triggers. Note that the 'btnCancel_Click' event is triggered before any validation is taking place. That is not so for the Form Closing events that will all execute after validating events. That is why that validation cannot be disabled from any of these Form Closing events.
c) For this 'Cancel' button to work correctly, you also need to set the 'CausesValidation' property of this 'Cancel' button to 'false'. This is necessary, otherwise clicking on this button will trigger the validation before validating can be disabled by the above 'AutoValidate = AutoValidate.Disable;' instruction.
At this point, you should be able to quit by clicking on the 'Cancel' button without having to first enter valid values. However, clicking the upper right "X" button of the form's window will still force validation.
3) Make the upper right "X" button also cancel validation:
The challenge here is to trap such "X" clicked event before validation is executed. Any attempt to do so through a Form Closing handler will not work because it is then too late once execution reaches such handler. However, the click of the "X" button can be captured promptly via overriding the WndProc() method and testing for a 'm.Msg == 0x10' condition. When that condition is true, the previously introduced 'AutoValidate = AutoValidate.Disable;' instruction can again be used to disable overall validation in that case as well. See the WndProc() method below for a code sample of such method. You should be able to copy and paste that method as is in your form's class.
At this point, both the 'Cancel' an "X" buttons should cancel valdations. However, the escape key that can be used to close a form does not. Such escape key is activated when the form's 'CancelButton' property is used to link this escape key to the form's 'Cancel' button.
4) Make the escape key also cancel validation:
Similar to the "X" button, the escape key can be captured by overriding an existingmethod. That is the ProcessDialogKey() method. One more time, the previously introduced 'AutoValidate = AutoValidate.Disable;' instruction can be used to disable overall validation for the escape key as well. See the ‘ProcessDialogKey()’ overridden method in the code below to see how this can be done. Here again, you should be able to copy and paste that method as is in your own form's class.
At this point you should be done!
Further considerations:
It is good to notice that the following two other ways to close the window should also work fine at this point. These two ways are:
The 'Close' option of the upper left window icon button.
Pressing Alt+F4 which triggers the same closing action as the above 'Close' option.
These two ways of closing the window started to also cancel validation once you introduced the "X" button capture mechanism described in point 3 above.
That is it for me for this so far. Hoping this helps!
My code sample below:
public partial class frmMyIP : Form
{
public frmMyIP()
{
InitializeComponent();
}
// To capture the Upper right "X" click
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x10) // The upper right "X" was clicked
{
AutoValidate = AutoValidate.Disable; //Deactivate all validations
}
base.WndProc(ref m);
}
// To capture the "Esc" key
protected override bool ProcessDialogKey(Keys keyData)
{
if (keyData == Keys.Escape)
{
AutoValidate = AutoValidate.Disable;
btnCancel.PerformClick();
return true;
}
return base.ProcessDialogKey(keyData);
}
public bool IsValidIP(string ipaddr)
{
string pattern = #"^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"+
#"(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$";
Regex check = new Regex(pattern);
bool valid = false;
if (ipaddr == "")
{
valid = false;
}
else
{
valid = check.IsMatch(ipaddr, 0);
}
return valid;
}
private void txtIPAddress_Validating(object sender, CancelEventArgs e)
{
string address = txtIPAddress.Text;
if (!IsValidIP(address))
{
MessageBox.Show("Invalid IP address!");
e.Cancel = true;
}
}
private void cmbMaskBits_Validating(object sender, CancelEventArgs e)
{
int MaskBitsValue = Convert.ToInt32(cmbMaskBits.Text);
if (MaskBitsValue<1 || MaskBitsValue>30)
{
MessageBox.Show("Please select a 'Mask Bits' value between 1 and 30!");
e.Cancel = true;
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
// Stop the validation of any controls so the form can close.
// Note: The CausesValidation property of this <Cancel> button
// must also be set to false.
AutoValidate = AutoValidate.Disable;
this.Close();
}
Insert the following as the first line in the validation event of the textbox:
//Allow the form to be closed
if (this.ActiveControl.Equals(sender))
return;
Since the close event of the form is triggering validation and since that would (typically at least) be the only form event that would trigger validation we can make the assumption that any form event triggering validation is the close event.
The actual answer is ridiculously simple compared to all the suggestions here which involve hacks and extra superfluous code to undo something.
The "trick" is just to allow the focus to change and not fire validation from buttons on the form itself.
You can simply set two properties on the form:
MyForm.CausesValidation = false;
MyForm.AutoValidate = AutoValidate.EnableAllowFocusChange;
Et voila, form acts normal when you try to close it and validation still works following other inputs such as tab changing focus or mouse clicks.
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
// Assume that X has been clicked and act accordingly.
}
Create a closing event, then simply cancel your validator.
Try to set CauseValidation to false
or see here : How to skip Validating after clicking on a Form's Cancel button
Or try set this in formClosing event
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// CauseValidation to false or check
}
What you need is an implementation like the one described below, where it is assumed that you have a Save button and a Cancel button for the form:
public Form1()
{
// Disable validation in constructor
textBox.CausesValidation = false;
}
private void OnSaveClicked(object sender, EventArgs e)
{
textBox.CausesValidation = true;
if (ValidateChildren())
{
//
// Do saving of the form data or other processing here ....
//
Close();
}
//
// Set validation to false, as user may press Cancel next
//
textBox.CausesValidation = false;
}
private void OnCancelClicked(object sender, EventArgs e)
{
Close();
}
Check which button has focus in the validation check. If cancel button (and in my case a clear button), override. This is an inner method I call from my cell validating event handler. (Just realized it was a C# question, but you can translate)
Private Sub validateCell(ByVal tagDesc As String, ByVal userInput As String, ByVal legalRegex As String, ByVal regexDesc As String, ByVal e As DataGridViewCellValidatingEventArgs)
Dim match As Match = Regex.Match(userInput, legalRegex)
Dim matches = match.Groups()
Dim val = match.Value
If val.Length = 0 Or userInput.Length > val.Length Then
tagGrid.Rows(e.RowIndex).ErrorText = _
tagDesc & " must match pattern: " & regexDesc
If Me.Cancel_Button.Focused Or Me.clearButton.Focused Then
e.Cancel = False
tagGrid.Rows(e.RowIndex).ErrorText = ""
Else
e.Cancel = True
MsgBox(tagDesc & " must match pattern: " & regexDesc, MsgBoxStyle.Critical)
End If
Else
e.Cancel = False
tagGrid.Rows(e.RowIndex).ErrorText = ""
End If
End Sub
I came here in search of a simple method to cause a form to close when a Validating event handler raises an exception, reports it, and needs to force the form to close. After reading this topic and numerous others, followed by an afternoon of experimenting, I have made several discoveries, and developed a simple hack to force the form to close.
First things first, though; I discovered that when a Validating event calls this.Close() the FormClosingEventArgs.Cancel flag passed into its From_Closing event procedure is set to TRUE, effectively causing the event to cancel itself. Conversely, a normal Close event receives a FormClosingEventArgs.Cancel flag set to FALSE.
Since the Close method on a form takes no arguments, there is no direct way to force the issue, giving rise to the need for a hack. This article discusses a number of such hacks, but I think mine is much simpler to implement.
The hack starts with a simple form level Boolean variable.
bool _fExceptionIsFatal = false;
Other than defining a Form_Closing event handler, this is the only structural change required to the form.
The Form_Closing event is straightforward.
private void From1_Closing ( object sender , FormClosingEventArgs e )
{
if (this.CausesValidation )
{ // There is no sense repeating this procedure if another routine already did it.
DisableValidation ( );
} // if (this.CausesValidation )
if ( _fExceptionIsFatal )
{ // Cancel False == Allow form to close.
e.Cancel = false;
} // if ( _fExceptionIsFatal )
} // From1_Closing
Though DisableValidation is implemented as a local method of the current form, the same thing could be accomplished by passing a Form reference into a library routine, since a Form is a Form, and its Controls collection is a Controls collection, period. Before long, I'll do so, along with implementing its inverse, to turn validation on again.
private void DisableValidation ( )
{
foreach ( Control ctrl in this.Controls )
{
ctrl.CausesValidation = false;
} // foreach ( Control ctrl in this.Controls )
this.CausesValidation = false;
} // DisableValidation
The fourth piece of the solution is equally straightforward; whenever you want to force the form to close, set _intValueAsInteger to TRUE before you call this.Close.
Add below code to your form. You can close the form even the children controls are validating.
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x10) // The upper right "X" was clicked
{
this.ActiveControl = null;
this.AutoValidate = AutoValidate.Disable;
}
base.WndProc(ref m);
}
This question is pretty old but thought of adding the answer anyway:
In the form constructor:
this.FormClosing += Form1_FormClosing;
In the closing event handler (Make sure CausesValidation for the form is set to true to begin with. You could also check the textbox's CausesValidation property instead of the form's) :
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (this.CausesValidation)
{
DisableValidation();
this.Close();
}
}
In the DisableValidation method, disable validation for the textboxes and the form (I am using 2):
private void DisableValidation()
{
txtbox1.CausesValidation = false;
txtbox2.CausesValidation = false;
CausesValidation = false;
}
I use C#.
I have a Windows Form with an edit box and a Cancel button. The edit box has code in validating event. The code is executed every time the edit box loses focus. When I click on the Cancel button I just want to close the form. I don't want any validation for the edit box to be executed. How can this be accomplished?
Here is an important detail: if the validation fails, then
e.Cancel = true;
prevents from leaving the control.
But when a user clicks Cancel button, then the form should be closed no matter what. how can this be implemented?
If the validation occurs when the edit box loses focus, nothing about the the cancel button is going to stop that from happening.
However, if the failing validation is preventing the cancel button from doing its thing, set the CausesValidation property of the button to false.
Reference: Button.CausesValidation property
Obviously CausesValidation property of the button has to be set to false and then the validating event will never happen on its click. But this can fail if the parent control of the button has its CausesValidation Property set to true. Most of the time developers misses/forgets to change the CausesValidation property of the container control (like the panel control). Set that also to False. And that should do the trick.
I was having problems getting my form to close, since the validation of certain controls was stopping it. I had set the control.CausesValidation = false for the cancel button and all the parents of the cancel button. But still was having problems.
It seemed that if the user was in the middle of editing a field that was using validation and just decided to give up (leaving the field with an invalid input), the cancel button event was being fired but the window would not close down.
This was fixed by the following in the cancel button click event:
private void btnCancel_Click(object sender, EventArgs e)
{
// Stop the validation of any controls so the form can close.
AutoValidate = AutoValidate.Disable;
Close();
}
Set the CausesValidation property of the Cancel button to false.
Set the CausesValidation property to false.
None of these answers quite did the job, but the last answer from this thread does. Basically, you need to:
Insure that the Cancel button (if any) has .CausesValidation set to false
Override this virtual method.
protected override bool ProcessDialogKey(Keys keyData) {
if (keyData == Keys.Escape) {
this.AutoValidate = AutoValidate.Disable;
CancelButton.PerformClick();
this.AutoValidate = AutoValidate.Inherit;
return true;
}
return base.ProcessDialogKey(keyData);
}
I didn't really answer this, just pointing to the two guys who actually did.
Setting CausesValidation to false is the key, however this alone is not enough. If the buttons parent has CausesValidation set to true, the validating event will still get called. In one of my cases I had a cancel button on a panel on a form, so I had to set CausesValidation = false on the panel as well as the form. In the end I did this programatically as it was simpler than going through all the forms...
Control control = cancelButton;
while(control != null)
{
control.CausesValidation = false;
control = control.Parent;
}
In my case, in the form I set the property AutoValidate to EnableAllowFocusChange
By using Visual Studio wizard you can do it like that:
Judicious use of the Control.CausesValidation property will help you achieve what you want.
Just above the validation code on the edit box add:
if (btnCancel.focused)
{
return;
}
That should do it.
In complement of the answer of Daniel Schaffer: if the validation occurs when the edit box loses focus, you can forbid the button to activate to bypass local validation and exit anyway.
public class UnselectableButton : Button
{
public UnselectableButton()
{
this.SetStyle(ControlStyles.Selectable, false);
}
}
or if you use DevExpress:
this.simpleButtonCancel.AllowFocus = false;
Note that doing so will change the keyboard experience: the tab will focus anymore on the cancel button.
Maybe you want to use BackgroundWorker to give little bit delay, so you can decide whether validation should run or not. Here's the example of avoiding validation on form closing.
// The flag
private bool _isClosing = false;
// Action that avoids validation
protected override void OnClosing(CancelEventArgs e) {
_isClosing = true;
base.OnClosing(e);
}
// Validated event handler
private void txtControlToValidate_Validated(object sender, EventArgs e) {
_isClosing = false;
var worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerAsync();
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
// Do validation on complete so you'll remain on same thread
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (!_isClosing)
DoValidationHere();
}
// Give a delay, I'm not sure this is necessary cause I tried to remove the Thread.Sleep and it was still working fine.
void worker_DoWork(object sender, DoWorkEventArgs e) {
Thread.Sleep(100);
}
This is an old question however I recently ran into this issue and solved it this way:
1st, we are loading a UserControl into a 'shell' Form that has a save and cancel button. The UserControl inherit an interface (like IEditView) that has functions for Save, Cancel, Validate and ToggleValidate.
In the shell form we used the mouse enter and mouse leave like so:
private void utbCancel_MouseEnter(object sender, EventArgs e)
{
((Interface.IEdit)tlpMain.Controls[1]).ToggleValidate();
}
private void utbCancel_MouseLeave(object sender, EventArgs e)
{
((Interface.IEdit)tlpMain.Controls[1]).ToggleValidate();
}
Then in ToggleValidate (Say a simple form with two controls...you can always just loop through a list if you want) we set the CausesValidation
public bool ToggleValidate()
{
uneCalcValue.CausesValidation = !uneCalcValue.CausesValidation;
txtDescription.CausesValidation = !txtDescription.CausesValidation;
return txtDescription.CausesValidation;
}
Hope this helps.
I found this thread today while investigating why my form would not close when a validation error occurred.
I tried the CausesValidation = false on the close button and on the form itself (X to close).
Nothing was working with this complex form.
While reading through the comments I spotted one that appears to work perfectly
on the form close event , not the close button (so it will fire when X is clicked also)
This did the trick.
AutoValidate = AutoValidate.Disable;
Create a bool:
bool doOnce;
Set it to false in your function and then:
if (doOnce == false)
{
e.cancel = true;
doOnce = true;
}
This means it will only run once and you should be able to cancel it. This worked for me anyways.
This work for me.
private void btnCancelar_MouseMove(object sender, MouseEventArgs e)
{
foreach (Control item in Form.ActiveForm.Controls)
{
item.CausesValidation = false;
}
}