Monday, June 09, 2003


Validation and Form Close

Ran into a weird one today.  We have a windows forms application that uses the validating event on it's controls.  When the user clicks the close box (red x) in the corner we want to prompt whether they would like to save and then close the form.

The validators cause problems with this.  Clicking on the close box causes validation to run. First blush you think no problem, I will set CausesValidation on the form to false.  Whoa!  The Validating event still fires.  It appears that the close box always causes validation. Next you think I will override OnClosing() and ask whether they want to save before calling the base implementation thus only allowing the Validating events to fire if they are saving.  Wrong again.  Validating fires before OnClosing!

So here is the hack I came up with.  Override WndProc in the form and look for the WM_CLOSE message.  If you receive it then set a protected member on the form to indicate it is currently closing.  I have this hidden in a base class that exposes the member as a read only property.

Here is some sample code:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace ValidationTest { /// <summary> /// Summary description for Form1. /// </summary> public class Form1 : System.Windows.Forms.Form { private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.TextBox textBox2; /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container components = null;

public Form1() { // // Required for Windows Form Designer support // InitializeComponent();

// // TODO: Add any constructor code after InitializeComponent call // }

/// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); }

#region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.textBox1 = new System.Windows.Forms.TextBox(); this.textBox2 = new System.Windows.Forms.TextBox(); this.SuspendLayout(); // // textBox1 // this.textBox1.Location = new System.Drawing.Point(80, 96); this.textBox1.Name = "textBox1"; this.textBox1.TabIndex = 0; this.textBox1.Text = "textBox1"; this.textBox1.Validating += new System.ComponentModel.CancelEventHandler(this.textBox1_Validating); // // textBox2 // this.textBox2.Location = new System.Drawing.Point(80, 128); this.textBox2.Name = "textBox2"; this.textBox2.TabIndex = 1; this.textBox2.Text = "textBox2"; // // Form1 // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(292, 273); this.Controls.Add(this.textBox2); this.Controls.Add(this.textBox1); this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false);

} #endregion

/// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.Run(new Form1()); }

// Constant for WM_CLOSE private const int WM_CLOSE = 16; // flag to indicate we are closing private bool m_bFormClosing = false;

protected virtual bool FormClosing { get { return m_bFormClosing; } }

private void textBox1_Validating(object sender, System.ComponentModel.CancelEventArgs e) { // Bail out if the form is in the process of closing if(FormClosing) return;

// Do my normal validation if(this.textBox1.Text == "invalid") { e.Cancel = true; MessageBox.Show("Invalid entry"); } }

protected override void WndProc(ref Message m) { // Check for the closing message if(m.Msg == WM_CLOSE) // Set our flag m_bFormClosing = true;

// Call the base base.WndProc (ref m); } } }

 

Wow that is ugly!  If anyone knows of a good C# -> HTML converter that works with Radio send me a pointer at mailto:ckinsman@vergentsoftware.com. This is from http://www.manoli.net/csharpformat/


2:58:19 PM