ESC and validation

M

Micky

VB v7.1.3088
NET v1.1.4322 SP1

My mate has a strange problem regarding the ESC key and validation. When he
hits the Cancel button on his form, the form does not validate. This is
correct behaviour of course. However, he also wants this same behaviour when
hitting ESC on the keyboard.

It was my understanding that when you assign a button to a form's
CancelButton property you automatically gained this functionality. However,
even when I tried it myself I found that not to be the case.

His btnCancel button has the DialogResult property set to Cancel and the
CausesValidation property set to False. The form's CancelButton property is
set to btnCancel.

It works just fine when clicked with the mouse (no validation), but when
hitting ESC it will always causes a validation, instead of simply firing the
btnCancel_Click event.

Does anyone know why ESC doesn't work as intended?

Thanks in advance.

Micky
 
K

Ken Tucker [MVP]

Hi,

When you press the esc key the form raises the cancel buttons click
event. My guess is that the form causesvalidation property is true while
your cancel button causesvalidation is false.

Ken
 
M

Micky

Ken Tucker said:
Hi,

When you press the esc key the form raises the cancel buttons click
event. My guess is that the form causesvalidation property is true while
your cancel button causesvalidation is false.

Ken
------------------
Thanks Ken, but it makes absolutely no difference whether the form's
CausesValidation property is true or false. I tried it both ways.

I even tried to intercept the keystrokes to manually bypass validation
when ESC was clicked. But both the KeyDown and KeyPress events
are suppressed by the validation. KeyUp *is* fired but only after
validation occurs--which is way too late for an interception.

I've written some very simple sample code (see below) and inserted
some tracers to see exactly how the execution actually flowed.

First, the results for valid data:

OK
txtCodename.Leave
txtCodename.Validating
txtCodename.Validated
btnOK.Click
frmEdit.Closing
frmEdit.Closed
<correct>

CANCEL
txtCodename.Leave
btnCancel.Click
frmEdit.Closing
frmEdit.Closed
<correct>

ENTER
txtCodename.Validating
txtCodename.Validated
btnOK.Click
frmEdit.Closing
frmEdit.Closed
<correct>

ESC
txtCodename.Validating
txtCodename.Validated
btnCancel.Click
frmEdit.Closing
frmEdit.Closed
<wrong>

Now the results for invalid data (the Validated event
should not fire):

OK
txtCodename.Leave
txtCodename.Validating
txtCodename.Enter
<correct>

CANCEL
txtCodename.Leave
btnCancel.Click
frmEdit.Closing
frmEdit.Closed
<correct>

ENTER
txtCodename.Validating
frmEdit.KeyUp
<correct>

ESC
txtCodename.Validating
frmEdit.KeyUp
<wrong>

As you can see, clicking the buttons in either case works as intended.
While the Enter key appears to work as intended in both cases, the
ESC key most certainly does not. btnCancel is definitely the form's
CancelButton so ESC should never CauseValidation--and yet it
clearly does.

Since the text box is clearly capturing the ESC key, is there any
way to tell it to ignore ESC. Seems to me there should be an
AcceptsESC property similar to AcceptsReturn or AcceptsTab--
except it should be read-only and set to False.

Anyhow, here's the code to demonstrate this problem. I'd be grateful
if anyone can determine where the problem lies (whether with my code
or with Microsoft's implementation of Validation). TIA.


Option Explicit On
Friend Class frmEdit
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents btnOK As System.Windows.Forms.Button
Friend WithEvents btnCancel As System.Windows.Forms.Button
Friend WithEvents ErrorProvider1 As System.Windows.Forms.ErrorProvider
Friend WithEvents lblCodename As System.Windows.Forms.Label
Friend WithEvents txtCodename As System.Windows.Forms.TextBox
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
Me.btnOK = New System.Windows.Forms.Button
Me.btnCancel = New System.Windows.Forms.Button
Me.ErrorProvider1 = New System.Windows.Forms.ErrorProvider
Me.txtCodename = New System.Windows.Forms.TextBox
Me.lblCodename = New System.Windows.Forms.Label
Me.SuspendLayout()
'
'btnOK
'
Me.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK
Me.btnOK.ImeMode = System.Windows.Forms.ImeMode.NoControl
Me.btnOK.Location = New System.Drawing.Point(184, 88)
Me.btnOK.Name = "btnOK"
Me.btnOK.Size = New System.Drawing.Size(88, 24)
Me.btnOK.TabIndex = 7
Me.btnOK.Tag = "OK"
Me.btnOK.Text = "&OK"
'
'btnCancel
'
Me.btnCancel.CausesValidation = False
Me.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel
Me.btnCancel.ImeMode = System.Windows.Forms.ImeMode.NoControl
Me.btnCancel.Location = New System.Drawing.Point(280, 88)
Me.btnCancel.Name = "btnCancel"
Me.btnCancel.Size = New System.Drawing.Size(88, 24)
Me.btnCancel.TabIndex = 6
Me.btnCancel.Tag = "Cancel"
Me.btnCancel.Text = "&Cancel"
'
'ErrorProvider1
'
Me.ErrorProvider1.ContainerControl = Me
'
'txtCodename
'
Me.ErrorProvider1.SetIconAlignment(Me.txtCodename, System.Windows.Forms.ErrorIconAlignment.MiddleLeft)
Me.ErrorProvider1.SetIconPadding(Me.txtCodename, 4)
Me.txtCodename.ImeMode = System.Windows.Forms.ImeMode.Off
Me.txtCodename.Location = New System.Drawing.Point(96, 32)
Me.txtCodename.MaxLength = 64
Me.txtCodename.Name = "txtCodename"
Me.txtCodename.Size = New System.Drawing.Size(272, 20)
Me.txtCodename.TabIndex = 1
Me.txtCodename.Tag = "Codename"
Me.txtCodename.Text = ""
Me.txtCodename.WordWrap = False
'
'lblCodename
'
Me.lblCodename.AutoSize = True
Me.lblCodename.ImeMode = System.Windows.Forms.ImeMode.NoControl
Me.lblCodename.Location = New System.Drawing.Point(8, 34)
Me.lblCodename.Name = "lblCodename"
Me.lblCodename.Size = New System.Drawing.Size(60, 16)
Me.lblCodename.TabIndex = 0
Me.lblCodename.Text = "Code&name"
'
'frmEdit
'
Me.AcceptButton = Me.btnOK
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.CancelButton = Me.btnCancel
Me.CausesValidation = False
Me.ClientSize = New System.Drawing.Size(378, 128)
Me.Controls.Add(Me.lblCodename)
Me.Controls.Add(Me.txtCodename)
Me.Controls.Add(Me.btnCancel)
Me.Controls.Add(Me.btnOK)
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog
Me.KeyPreview = True
Me.MaximizeBox = False
Me.MinimizeBox = False
Me.Name = "frmEdit"
Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
Me.Text = "Edit"
Me.ResumeLayout(False)
End Sub
#End Region
Private Sub btnCancel_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnCancel.Click
Debug.Write("btnCancel.Click" + _
vbCrLf)
End Sub
Private Sub btnOK_Click( _
ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles btnOK.Click
Debug.Write("btnOK.Click" + _
vbCrLf)
End Sub
Private Sub Field_Enter( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles txtCodename.Enter
Debug.Write("txt" + _
sender.Tag + _
".Enter" + _
vbCrLf + vbCrLf)
sender.SelectAll()
End Sub
Private Sub Field_Leave( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles txtCodename.Leave
Debug.Write("txt" + _
sender.Tag + _
".Leave" + _
vbCrLf)
End Sub
Private Sub txtCodename_Validating( _
ByVal sender As System.Object, _
ByVal e As System.ComponentModel.CancelEventArgs) _
Handles txtCodename.Validating
Debug.Write("txtCodename.Validating" + _
vbCrLf)
Dim errorMsg As String
If txtCodename.Text.Length = 0 Then
errorMsg = "Agent must have a codename."
e.Cancel = True
End If
Me.ErrorProvider1.SetError(txtCodename, errorMsg)
End Sub
Private Sub txtCodename_Validated( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles txtCodename.Validated
Debug.Write("txtCodename.Validated" + _
vbCrLf)
ErrorProvider1.SetError(txtCodename, "")
End Sub
Private Sub frmEdit_Closing( _
ByVal sender As Object, _
ByVal e As System.ComponentModel.CancelEventArgs) _
Handles MyBase.Closing
Debug.Write("frmEdit.Closing" + _
vbCrLf)
End Sub
Private Sub frmEdit_Closed( _
ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles MyBase.Closed
Debug.Write("frmEdit.Closed" + _
vbCrLf + vbCrLf)
End Sub
Private Sub frmEdit_KeyDown( _
ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) _
Handles MyBase.KeyDown
Debug.Write("frmEdit.KeyDown" + _
vbCrLf)
End Sub
Private Sub frmEdit_KeyPress( _
ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyPressEventArgs) _
Handles MyBase.KeyPress
Debug.Write("frmEdit.KeyPress" + _
vbCrLf)
End Sub
Private Sub frmEdit_KeyUp( _
ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) _
Handles MyBase.KeyUp
Debug.Write("frmEdit.KeyUp" + _
vbCrLf + vbCrLf)
End Sub
End Class
Module modMain
Public Sub Main()
Dim fEdit As New frmEdit
fEdit.ShowDialog()
End Sub
End Module
------------------
 
M

Micky

Under VB.NET 2003, ESC will always cause a validation. This is
because the control box raises two validations (instead of one), and
setting a form's CausesValidation to False merely supresses one of
those validations. In other words, clicking Cancel works as intended,
but hitting ESC does not.

I'm not sure if the same bug exists in VB.NET 2005, but if it does,
here's the workaround. Intercept the ESC key and close the form.
Validation then works as expected.

A few people seem to be aware of the bug, but no-one seems to
be aware of the workaround, so I guess you saw it here first. :)

' Include this function in any form that includes validation
Protected Overrides Function ProcessCmdKey( _
ByRef msg As System.Windows.Forms.Message, _
ByVal keyData As System.Windows.Forms.Keys) _
As Boolean
Const WM_KEYDOWN As Integer = &H100
If msg.Msg = WM_KEYDOWN Then
If keyData = Keys.Escape Then
Close() ' or raise the btnCancel.Click event
End If
End If
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
 
M

Micky

Sorry if this is a duplicate post. I don't see my original...

Under VB.NET 2003, ESC will always cause a validation. This is
because the control box raises two validations (instead of one), and
setting a form's CausesValidation to False merely supresses one of
those validations. In other words, clicking Cancel works as intended,
but hitting ESC does not.

I'm not sure if the same bug exists in VB.NET 2005, but if it does,
here's the workaround. Intercept the ESC key and close the form.
Validation then works as expected.

A few people seem to be aware of the bug, but I found no mention
of this workaround, so I guess you saw it here first. :)

' Include this function in any form that includes validation
Protected Overrides Function ProcessCmdKey( _
ByRef msg As System.Windows.Forms.Message, _
ByVal keyData As System.Windows.Forms.Keys) _
As Boolean
Const WM_KEYDOWN As Integer = &H100
If msg.Msg = WM_KEYDOWN Then
If keyData = Keys.Escape Then
Close() ' or raise the btnCancel.Click event
End If
End If
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top