Check if any control has changed and save data upon form closing

5.4k Views Asked by At

We are using vb.net / dev express tools. We have several controls textboxes, combos etc... instead of checking each value changed we want to go through all controls and check if anything has been edited, then save upon form closing. Below is some code i have tried to accomplish this. Problem is, although it technically works... it uses recursion AddDirtyEvent(c) , so when i go to close the form and click yes to save.. it calls that messagebox multiple times due to multiple controls... if i take that out , it won't work and detect the dirty change. I'm just wondering how can i get this to work the way i want or if there is an easier way...

 Dim is_Dirty As Boolean = False

  Private Sub AddDirtyEvent(ByVal ctrl As Control)

    For Each c As Control In ctrl.Controls
        If TypeOf c Is TextEdit Then
            Dim tb As TextEdit = CType(c, TextEdit)
            AddHandler tb.EditValueChanged, AddressOf SetIsDirty

        End If
        'If TypeOf c Is ComboBoxEdit Then
        '    Dim cb As ComboBoxEdit = CType(c, ComboBoxEdit)
        '    AddHandler cb.SelectedIndexChanged, AddressOf SetIsDirty

        'End If
        If c.Controls.Count > 0 Then
            AddDirtyEvent(c)
        End If

    Next

End Sub

Private Sub SetIsDirty(ByVal sender As System.Object, ByVal e As System.EventArgs)
    is_Dirty = True
End Sub

Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing

    If is_Dirty = True Then
        Dim dr As DialogResult = MessageBox.Show("Do you want save changes before leaving?", "Closing Well Info", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2)
        If dr = Windows.Forms.DialogResult.Yes Then
            SimpleButtonSave.PerformClick()
            Me.Close()
        End If
    End If
End Sub
2

There are 2 best solutions below

0
On BEST ANSWER

The part of your code that handles the events and sets the dirty flag works OK.

Your MessageBox appears multiple times because you are calling Me.Close within the FormClosing event handler. Calling Close triggers the FormClosing event again - recursively. Just remove the Me.Close; the form is already closing.

0
On

As an ex MS access programmer I was also quite eager to develop an implementation of a form dirty property for vb.net, I find it more user friendly (and my users are used to it) to detect change of a control on a form or leaving a dirty form and ask for confirmation rather then the classical edit and save buttons. I previously created custom controls in a library for textbox, combobox, listbox etc... as I like the control having the focus to have a different background and ability to zoom text etc...

So I added to them (textbox code):

>    Protected Overrides Sub OnModifiedChanged(e As EventArgs)
>        MyBase.OnModifiedChanged(e)
>        If _DirtyEnabled and Me.Modified Then FormDirty(Me) = Me.Modified
>    End Sub
>    Private _DirtyEnabled As Boolean = False
>    <Category("Misc"), Description("When Enabled triggers Dirty event for form"), Browsable(True)> _
>    Public Property DirtyEnabled As Boolean
>        Get
>            Return _DirtyEnabled
>        End Get
>        Set(value As Boolean)
>            DirtyEnabled = value
>        End Set
>    End Property

This is for a textbox, For combobox and listbox I used the SelectIndexChanged event. If the DirtyEnabled Property is set to True then any change would trigger a call of FormDirty property. Then in a public module of the library:

>    #Region "Dirty"
>    Private Structure FormInfo  ' used in DirtyForm dictionary to keep a list of dirty forms
>        Dim Name As String
>        Dim Time As Date
>        Dim Ctrl As String
>    End Structure
>    Private DirtyForms As New Dictionary(Of IntPtr, FormInfo)     ' key = form handle as the form could be opened more then once, value FormInfo
>
>     Public Property FormDirty(frm As Form) As Boolean
>        Get
>            If DirtyForms.Count > 0 Then
>                Return DirtyForms.ContainsKey(frm.Handle)
>            Else
>                Return False
>            End If
>        End Get
>        Set(IsDirty As Boolean)
>            EditDirtyForms(frm, IsDirty)
>        End Set
>    End Property
>
>    Public Property FormDirty(Ctrl As Control) As Boolean
>        Get
>            If DirtyForms.Count > 0 Then
>                 Return DirtyForms.ContainsKey(Ctrl.FindForm.Handle)
>             Else
>                 Return False
>             End If
>        End Get
>        Set(IsDirty As Boolean)
>            EditDirtyForms(Ctrl.FindForm, IsDirty, Ctrl.Name)
>        End Set
>    End Property
>
>    Private Sub EditDirtyForms(frm As Form, IsDirty As Boolean, Optional CtrlName As String = Nothing)
>        If IsDirty Then
>            If DirtyForms.Count = 0 OrElse Not DirtyForms.ContainsKey(frm.Handle) Then
>                Dim Info As New FormInfo With {.Name = frm.Name, .Time = Now, .Ctrl = CtrlName}
>                DirtyForms.Add(frm.Handle, Info)
>            End If
>        ElseIf DirtyForms.Count > 0 Then
>            If DirtyForms.ContainsKey(frm.Handle) Then DirtyForms.Remove(frm.Handle)
>        End If
>    End Sub
>
>    Public Function DirtyFormList() As String
>        Dim p As New FormInfo, s As String = String.Empty
>        If DirtyForms.Count > 0 Then
>            For Each f As KeyValuePair(Of IntPtr, FormInfo) In DirtyForms
>                s &= f.Value.Name & cSpace & If(f.Value.Ctrl, String.Empty) & ": " & f.Value.Time & vbNewLine
>            Next
>        End If
>        Return s
>    End Function
>
>    Public Function DirtyFormCount() As Integer
>        Return DirtyForms.Count
>    End Function
> #End Region

A forms save would call Formdirty(me) = False It's still in test phase and still misses asking confirmation from the user etc... It works but as I am quite new in .net programming any comment or critic is very welcome.

rgds