In my application, i have put a question on form closing if the user wants to save the changes?. But right now, i have just put it in default whether they make changes or not.
I thought of prompting it on text change.. but the text automatically changes on load as it retrieves data from sql server. is there a way to rectify this?

yes i think you have to put your code at the got focus of that textbox , because without getting focus no change can be performed.

Regards

is there any other way? because each of my forms carry atleast 15 to 20 textboxes, not to mention, comboboxes, listviews, datagrid view, checkboxes and radio buttons. setting an on focus for all of them will take lot of code. I'm sorry. i'm new to vb. could i just do it with a function? or is there a way to cycle through all elements on the form?

Add two Booleans to your Global Variables set to False

Dim loaded As Boolean = False
Dim txtChanged As Boolean = False

Create a Sub to handle when any of the Text Boxes have a Text Changed event, say set a flag to true.

Private Sub Text_Changed(ByVal sender As Object, ByVal e As System.EventArgs)
    If loaded Then
      txtChanged = True
    End If
  End Sub

In the Forms Load - loop through all the controls setting this Sub as the handler for your textboxes Text Changed event, after all SQL transactions have been completed set the loaded flag to true. This will prevent the txtChanged flag from being set to true until the user changes the text.

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
    For Each cntrl As Control In Me.Controls
      If TypeOf (cntrl) Is TextBox Then
        AddHandler cntrl.TextChanged, AddressOf Text_Changed
      End If
    Next

    'Simulated SQL DATA Being Added
    TextBox1.Text = "TEST DATA"
    TextBox2.Text = "TEST DATA"
    TextBox3.Text = "TEST DATA"
    TextBox4.Text = "TEST DATA"
    TextBox5.Text = "TEST DATA"
    TextBox6.Text = "TEST DATA"
    loaded = True
  End Sub

When the Form is Closing Check the txtChanged flag and act accordingly

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    If txtChanged Then
      MsgBox("THE USER SHOULD BE PROMPTED TO SAVE")
    Else
      MsgBox("NO CHANGES HAVE BEEN MADE")
    End If
  End Sub

Once the form has loaded and the text fields have been populated, you could loop through the text boxes and make a copy of the contained text in the Tag property of each control. Of form close you could compare the values of TextBox#.Text to TextBox#.Tag to look for changes.

hey phasma, I tried your method, but the text cycling doesnt go through those within groupboxes for some reason.

i tried changing this code a little bit

For Each cntrl As Control In Me.Controls
      If TypeOf (cntrl) Is TextBox Then
        AddHandler cntrl.TextChanged, AddressOf Text_Changed
      End If
    Next

i used a function

Public Shared Function FindControlRecursive(ByVal list As List(Of Control), ByVal parent As Control, ByVal ctrlType As System.Type) As List(Of Control)
        If parent Is Nothing Then Return list
        If parent.GetType Is ctrlType Then
            list.Add(parent)
        End If
        For Each child As Control In parent.Controls
            FindControlRecursive(list, child, ctrlType)
        Next
        Return list
    End Function
Dim allTxt As New List(Of Control)
        For Each txt As TextBox In FindControlRecursive(allTxt, Me, GetType(TextBox))
            
            AddHandler Control.TextChanged, AddressOf Text_Changed

        Next

but apparently this doesn't work either... i know i'm close. any suggestions?

You will have to loop through each GroupBox just as you did with the form1 ---> "Me"

commented: helpful +1

You will have to loop through each GroupBox just as you did with the form1 ---> "Me"

Thank You Phamsa. In a fashion it works.

For Each cntrl As Control In Me.GroupBox1.Controls
            If TypeOf (cntrl) Is TextBox Then
                AddHandler cntrl.TextChanged, AddressOf Text_Changed
            End If
        Next
        For Each cntrl As Control In Me.GroupBox2.Controls
            If TypeOf (cntrl) Is TextBox Then
                AddHandler cntrl.TextChanged, AddressOf Text_Changed
            End If
        Next
        For Each cntrl As Control In Me.GroupBox3.Controls
            If TypeOf (cntrl) Is TextBox Then
                AddHandler cntrl.TextChanged, AddressOf Text_Changed
            End If
        Next
        For Each cntrl As Control In Me.GroupBox4.Controls
            If TypeOf (cntrl) Is TextBox Then
                AddHandler cntrl.TextChanged, AddressOf Text_Changed
            End If
        Next
        loaded = True

only problem being, as soon as the form is loaded, it populates data into the textfields from the database which triggers the textchange which thereby prompts the user to save. I guess i'll have to work around this. Thanks though.

but if the text is made blank again, it still asks to save?, hw will i proceed from here.

That's why I suggested saving the original string in the Tag property. You don't have to worry about bogus Changed events like when the value is originally set, or if the user modifies a field, then undoes the mod. As long as the text is the same at the start and the end you don't really care if it was changed in between. By comparing the Tag to the Text all you have to do is

'pseudo code

changed = False

for each text control
    if control.Text <> control.Tag then
        changed = True
        exit for
    end if
next

If changed Then
    prompt to save changes
Else
    no changes made
End If

Easier and cleaner than having to add extra handlers and you can use a spare property in the control (Tag) instead of creating local variables.

Great it worked man!! thnx Reverend Jim!!

I didn't know it could be done in that way.

Not related to the solved thread, though I hope it helps to minimize less lines of code.

For Each grp In New GroupBox() {GroupBox1, GroupBox2, GroupBox3, GroupBox4}
            For Each ctl As Control In grp.Controls
                If TypeOf (ctl) Is TextBox Then
                    AddHandler ctl.TextChanged, AddressOf Text_Changed
                End If
            Next
        Next

Btw, why not just set the .Tag of each TextBox to something as "1" if it contains .Text and .Text has changed, and "0" if all ok?

hey codeorder, the reason being as i stated earlier, the form on load populates data immediately from the Db. so textchange happens on load whatever happens. that is why an ordinary text change condition wudn help.

Then populate the TextBoxes first and add handlers to the Text_Changed event right after.
If you need to give it time to populate them, use Application.DoEvents just prior to assigning them the Text_Changed event.

You can also remove the handlers if ever needing to repopulate and then assign the handlers back.

but if the text is made blank again, it still asks to save?, hw will i proceed from here.

I solved this problem by creating hidden text boxes for each text box/combo that stored the original text box/ combo value. Also, a hidden check box (f_DataChanged). The coding is a bit cumbersome cause I'm no expert but it works. Call this sub from the TextChanged event of each text box. I used:

Private Sub DataChangeCheck()
        Dim DataChanged As Integer = 0
        If Not Me.Txt_ContactName.Text = Me.Txt_OrigContactName.Text Then
            DataChanged = DataChanged + 1
        End If

       'Etc......More controls here

        If DataChanged > 0 Then
            Me.f_DataChanged.CheckState = 1
        Else
            Me.f_DataChanged.CheckState = 0
        End If

    End Sub
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.