Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Dirty Button

0.00/5 (No votes)
30 Aug 2007 2  
A button control that keeps track of the form’s dirty state.

Screenshot - dirtybutton.gif

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 GroupBoxes. 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 GroupBoxes 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 MonitoredControls, 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?

History

  • 2.0: Bug fixes and new functions added. Please see the text above.
  • 1.0: Initial release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here