When you do a project where the user has to fill in a lot of information, you often want to know if there has been changes made or not so that you can enable a Save button accordingly. Normally, you would put a Boolean variable in your code (e.g.,
bDirtyBit) and enter some code in each control's Change event (e.g.,
In the project I'm currently working on, I've got forms with hundreds of controls, and entering code into each control's Change event is very tiresome. Plus, it's very easy to miss a control when you add new controls. Also, it's a lot of unnecessary code that makes the really important code harder to read.
So, I decided to do a special button control that can handle all that automatically for me without any coding (actually, somebody else suggested the idea, but didn't know how to implement it). And, that's what I did. The button is very basic. It keeps track of all the important controls on your form, and enables the button if a change has been made. Thus, it keeps your code free of all the abovementioned, unnecessary code.
The project also demonstrates how you can use an Extender Provider to add properties to other controls. It is a lot easier than you would think...
This is my first submission to The Code Project, so I hope everything is OK. If you encounter any problems, please don't hesitate to contact me.
Using the code
The use of the control is extremely simple. Just drop it on your form and add this code to the
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
These basic controls are monitored for changes:
**** New in Version 2.0 ****
- The button adds a property to the monitorable controls called
DirtyMonitored (similar to the way the
Tooltip component adds a
ToolTip property). If you have a single control of the type above on the form (or more than one) that you do not want to include in the monitoring process, simply set that property to
False – and voila: it is omitted.
Please note: These properties are not really added to the controls themselves. They are actually a part of the
DirtyButton. So, they're only visible at design time. That means that you cannot use code like this:
TextBox17.DirtyMonitored=True at runtime. You can call
DirtyButton.SetDirtyMonitored(Textbox17), but it will have no effect if you do it after calling the
StartMonitoring method. In that case, you will probably have to call
EndMonitoring and then
StartMonitoring again, but I haven't tried it, so I'm not 100% certain it works.
And, these controls are not monitored (because from what criteria/event would we enable the button?):
You can set the dirty state manually if the controls above are changed in a way that you consider relevant, using:
There are a few other methods and properties that are good to know:
I "accidentally" noticed that there was a bug in my initial control. If you place the
SetDirtyOnButtonClick etc. All of these are practically self-explanatory, very simple to use, and the use is shown in the demo project.
DirtyButton in a
GroupBox, it is only the controls nested in that
GroupBox that are monitored. Not the controls outside or in other
GroupBoxes. That is because I used the
Parent property to determine where the
DirtyButton was located, not the
But then I thought: well, maybe somebody likes it that way, and wants to have two or more
GroupBoxes each with their own
DirtyButton. Other people might want the button to monitor the whole form even if it's in a
So, instead of fixing the bug, I simply made it a property of the button:
I added a
MonitoringScope, which can be set to
ParentOnly. That solved that problem!
DirtyStateChanged event for the
DirtyButton control. It fires when the button changes
DirtyState, both when it becomes clean and when it becomes dirty. In the
EventArgs, you get the state as a boolean plus the control that caused the change. In the demo project, you can see how you can find the name of that control.I did some changes in the
EndMonitoring routine. In version 1.0, I simply stopped monitoring the controls, but I left the event handlers where they where. In this version, I decided to do some cleaning up, and am now removing the event handlers.Ulan Bator is no longer a country but a city... It is far away, though... ;-)
Possible improvements in upcoming versions
The ability to add custom and third party controls to the monitoring process would be nice, but was not necessary for me at this stage.
DirtyControls etc. as per request... :-)
As it is now, controls that are added at runtime aren't included unless you call the
StartMonitoring method after they are added. But, how often do you add controls at runtime?
- 2.0: Bug fixes and new functions added. Please see the text above.
- 1.0: Initial release.