Introduction
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., bDirtyBit=True
or cmdSave.Enabled=True
).
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 Form_Load
event:
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
DirtyButton1.StartMonitoring()
End Sub
These basic controls are monitored for changes: CheckBox
, ComboBox
, DateTimePicker
, MaskedTextBox
, MonthCalendar
, NumericUpDown
, RadioButton
, RichTextBox
, TextBox
, Button
(optional).
**** 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?): Label
, LinkLabel
, ListBox
, ListView
, NotifyIcon
, PictureBox
, ProgressBar
, ToolTip
, TreeView
, and WebBrowser
.
You can set the dirty state manually if the controls above are changed in a way that you consider relevant, using:
DirtyButton1.SetDirtyState()
There are a few other methods and properties that are good to know: ResetDirtyState
, IsDirty
, SuspendMonitoring
, ResumeMonitoring
, SetDirtyOnButtonClick
etc. All of these are practically self-explanatory, very simple to use, and the use is shown in the demo project.
I "accidentally" noticed that there was a bug in my initial control. If you place the DirtyButton
in a GroupBox
, it is only the controls nested in that GroupBox
that are monitored. Not the controls outside or in other GroupBox
es. That is because I used the Parent
property to determine where the DirtyButton
was located, not the FindForm
method.
But then I thought: well, maybe somebody likes it that way, and wants to have two or more GroupBox
es each with their own DirtyButton
. Other people might want the button to monitor the whole form even if it's in a GroupBox
.
So, instead of fixing the bug, I simply made it a property of the button: MonitoringScope
, which can be set to WholeForm
or ParentOnly
. That solved that problem!
I added a 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.
Collections for MonitoredControl
s, DirtyControl
s 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?
History
- 2.0: Bug fixes and new functions added. Please see the text above.
- 1.0: Initial release.