How do "dirty checking" with a Windows Form?

  • Thread starter Thread starter Dave
  • Start date Start date
D

Dave

How do I check in a Windows Forms app if any controls have changed? I have
a form that collects data, and I want to prompt the user if they try to exit
the app, or load a new file, without saving changes that have been made.

In MFC/Win32, you'd trap the WM_COMMAND/EN_CHANGE notification messages,
etc. But, this doesn't seem to happen in Windows Forms. I tried Spy-ing a
windows forms app, and the WM_COMMAND messages don't even get sent (!).

Thanks!

- Dave
 
Have event handlers on the controls. Multiple controls can all call the same
event handler.
 
Ok, but I'm using standard controls. Isn't there a standard notification
event that controls send to their parent in Windows Forms, notifying the
parent that the control has changed? I'm pretty sure there must be an easy
way to do this - there is in Win32, and I doubt they'd have gotten rid of
such basic functionality when it was wrapped with .net.
 
I dont know about Win32, but as bonj says what you want can be done simply
by suscribing a standard event handler to each controls changed event (or
relevent event for that control). Use a private bool to remember the state.
You are writing about 5 lines of code (and one for each new control added to
the form) simple e.g.

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

namespace WindowsApplication6
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private bool dataChanged = false;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.Button buttonClose;
private System.Windows.Forms.Button buttonSave;
/// <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.buttonClose = new System.Windows.Forms.Button();
this.buttonSave = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(32, 32);
this.textBox1.Name = "textBox1";
this.textBox1.TabIndex = 0;
this.textBox1.Text = "textBox1";
this.textBox1.TextChanged += new
System.EventHandler(this.formControlChanged);
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(32, 72);
this.textBox2.Name = "textBox2";
this.textBox2.TabIndex = 1;
this.textBox2.Text = "textBox2";
this.textBox2.TextChanged += new
System.EventHandler(this.formControlChanged);
//
// buttonClose
//
this.buttonClose.Location = new System.Drawing.Point(192, 216);
this.buttonClose.Name = "buttonClose";
this.buttonClose.TabIndex = 2;
this.buttonClose.Text = "&Close";
this.buttonClose.Click += new
System.EventHandler(this.buttonClose_Click);
//
// buttonSave
//
this.buttonSave.Location = new System.Drawing.Point(112, 216);
this.buttonSave.Name = "buttonSave";
this.buttonSave.TabIndex = 3;
this.buttonSave.Text = "&Save";
this.buttonSave.Click += new System.EventHandler(this.buttonSave_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.buttonSave);
this.Controls.Add(this.buttonClose);
this.Controls.Add(this.textBox2);
this.Controls.Add(this.textBox1);
this.Name = "Form1";
this.Text = "Form1";
this.Closing += new
System.ComponentModel.CancelEventHandler(this.Form1_Closing);
this.ResumeLayout(false);

}
#endregion

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

private void formControlChanged(object sender, System.EventArgs e)
{
this.dataChanged = true;
}

private void buttonClose_Click(object sender, System.EventArgs e)
{
this.Close();
}

private void Form1_Closing(object sender,
System.ComponentModel.CancelEventArgs e)
{
if (this.dataChanged)
{
e.Cancel = true;
MessageBox.Show("Warning! Data has changed and must be saved");
}

}

private void buttonSave_Click(object sender, System.EventArgs e)
{
//data saved
this.dataChanged = false;
}

}
}
 
Thanks, Mark. Yes, I finally figured out pretty much the same thing. Kind
of a hassle if you have lots of controls, though. In Win32, the controls
are sending the change event to the parent without having to subscribe.
Easier. There is an easier way than having a separate handler for each
control, though - you can use the same handler for each control of the same
type.

- Dave
Mark Broadbent said:
I dont know about Win32, but as bonj says what you want can be done simply
by suscribing a standard event handler to each controls changed event (or
relevent event for that control). Use a private bool to remember the state.
You are writing about 5 lines of code (and one for each new control added to
the form) simple e.g.

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

namespace WindowsApplication6
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private bool dataChanged = false;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.Button buttonClose;
private System.Windows.Forms.Button buttonSave;
/// <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.buttonClose = new System.Windows.Forms.Button();
this.buttonSave = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(32, 32);
this.textBox1.Name = "textBox1";
this.textBox1.TabIndex = 0;
this.textBox1.Text = "textBox1";
this.textBox1.TextChanged += new
System.EventHandler(this.formControlChanged);
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(32, 72);
this.textBox2.Name = "textBox2";
this.textBox2.TabIndex = 1;
this.textBox2.Text = "textBox2";
this.textBox2.TextChanged += new
System.EventHandler(this.formControlChanged);
//
// buttonClose
//
this.buttonClose.Location = new System.Drawing.Point(192, 216);
this.buttonClose.Name = "buttonClose";
this.buttonClose.TabIndex = 2;
this.buttonClose.Text = "&Close";
this.buttonClose.Click += new
System.EventHandler(this.buttonClose_Click);
//
// buttonSave
//
this.buttonSave.Location = new System.Drawing.Point(112, 216);
this.buttonSave.Name = "buttonSave";
this.buttonSave.TabIndex = 3;
this.buttonSave.Text = "&Save";
this.buttonSave.Click += new System.EventHandler(this.buttonSave_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.buttonSave);
this.Controls.Add(this.buttonClose);
this.Controls.Add(this.textBox2);
this.Controls.Add(this.textBox1);
this.Name = "Form1";
this.Text = "Form1";
this.Closing += new
System.ComponentModel.CancelEventHandler(this.Form1_Closing);
this.ResumeLayout(false);

}
#endregion

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

private void formControlChanged(object sender, System.EventArgs e)
{
this.dataChanged = true;
}

private void buttonClose_Click(object sender, System.EventArgs e)
{
this.Close();
}

private void Form1_Closing(object sender,
System.ComponentModel.CancelEventArgs e)
{
if (this.dataChanged)
{
e.Cancel = true;
MessageBox.Show("Warning! Data has changed and must be saved");
}

}

private void buttonSave_Click(object sender, System.EventArgs e)
{
//data saved
this.dataChanged = false;
}

}
}



Dave said:
Ok, but I'm using standard controls. Isn't there a standard notification
event that controls send to their parent in Windows Forms, notifying the
parent that the control has changed? I'm pretty sure there must be an
easy
way to do this - there is in Win32, and I doubt they'd have gotten rid of
such basic functionality when it was wrapped with .net.
 
Yes you are right (my code only used one handler for each of the textboxes).
There is a slightly easier way to implement this (if you have loads of
controls) and that would be to loop through the forms control collection and
assign the delegate handler to each (conditionally if required). You could
therefore write a reusable bit of code to do this.
Anyhow good luck with the coding.
Br,

Mark.


Dave T said:
Thanks, Mark. Yes, I finally figured out pretty much the same thing.
Kind
of a hassle if you have lots of controls, though. In Win32, the controls
are sending the change event to the parent without having to subscribe.
Easier. There is an easier way than having a separate handler for each
control, though - you can use the same handler for each control of the
same
type.

- Dave
Mark Broadbent said:
I dont know about Win32, but as bonj says what you want can be done
simply
by suscribing a standard event handler to each controls changed event (or
relevent event for that control). Use a private bool to remember the state.
You are writing about 5 lines of code (and one for each new control added to
the form) simple e.g.

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

namespace WindowsApplication6
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private bool dataChanged = false;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.Button buttonClose;
private System.Windows.Forms.Button buttonSave;
/// <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.buttonClose = new System.Windows.Forms.Button();
this.buttonSave = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(32, 32);
this.textBox1.Name = "textBox1";
this.textBox1.TabIndex = 0;
this.textBox1.Text = "textBox1";
this.textBox1.TextChanged += new
System.EventHandler(this.formControlChanged);
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(32, 72);
this.textBox2.Name = "textBox2";
this.textBox2.TabIndex = 1;
this.textBox2.Text = "textBox2";
this.textBox2.TextChanged += new
System.EventHandler(this.formControlChanged);
//
// buttonClose
//
this.buttonClose.Location = new System.Drawing.Point(192, 216);
this.buttonClose.Name = "buttonClose";
this.buttonClose.TabIndex = 2;
this.buttonClose.Text = "&Close";
this.buttonClose.Click += new
System.EventHandler(this.buttonClose_Click);
//
// buttonSave
//
this.buttonSave.Location = new System.Drawing.Point(112, 216);
this.buttonSave.Name = "buttonSave";
this.buttonSave.TabIndex = 3;
this.buttonSave.Text = "&Save";
this.buttonSave.Click += new System.EventHandler(this.buttonSave_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.buttonSave);
this.Controls.Add(this.buttonClose);
this.Controls.Add(this.textBox2);
this.Controls.Add(this.textBox1);
this.Name = "Form1";
this.Text = "Form1";
this.Closing += new
System.ComponentModel.CancelEventHandler(this.Form1_Closing);
this.ResumeLayout(false);

}
#endregion

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

private void formControlChanged(object sender, System.EventArgs e)
{
this.dataChanged = true;
}

private void buttonClose_Click(object sender, System.EventArgs e)
{
this.Close();
}

private void Form1_Closing(object sender,
System.ComponentModel.CancelEventArgs e)
{
if (this.dataChanged)
{
e.Cancel = true;
MessageBox.Show("Warning! Data has changed and must be saved");
}

}

private void buttonSave_Click(object sender, System.EventArgs e)
{
//data saved
this.dataChanged = false;
}

}
}



Dave said:
Ok, but I'm using standard controls. Isn't there a standard notification
event that controls send to their parent in Windows Forms, notifying
the
parent that the control has changed? I'm pretty sure there must be an
easy
way to do this - there is in Win32, and I doubt they'd have gotten rid of
such basic functionality when it was wrapped with .net.

"Bonj" <benjtaylor at hotpop d0t com> wrote in message
Have event handlers on the controls. Multiple controls can all call
the
same
event handler.

How do I check in a Windows Forms app if any controls have changed? I
have
a form that collects data, and I want to prompt the user if they try to
exit
the app, or load a new file, without saving changes that have been
made.

In MFC/Win32, you'd trap the WM_COMMAND/EN_CHANGE notification
messages,
etc. But, this doesn't seem to happen in Windows Forms. I tried
Spy-ing
a
windows forms app, and the WM_COMMAND messages don't even get sent (!).

Thanks!

- Dave
 
Back
Top