Save changes before choosing another Listbox record

When making a change in a textfield, the ButtonSave.enabled = true so the user knows that he has to save the changes to the DB. However if he doesn’t notice the Enabled Save Button and clicks on another row in the Listbox to which the text fields are connected, the changes will be lost. I can show a popup window saying “Save or otherwise the changes will be lost”, but this doesn’t work correctly because the listbox selection is lost already and the changes in the connected textfields are lost.

How can I prevent the Listbox from going to another row so the user can click the Save button first?

Are you using LostFocus/FocusLost for the textfield?
Maybe you can save the information and the reference to the connected textfield to some properties so that information is not lost until after the user confirms or deny the save?

Yes, I added this code in the FocusLost event of the textfield:

if winmain.btnUpdateCharInfo.enabled = true then
  MessageBox("Please click the Update Button first to save changes.")
  Return
end if

But the Listbox selected row is then already changed. I will play around the Properties idea, thanks.

Using a window property ‘recordModified’ (boolean true, false) as a semaphore allows conservation of the status.

I added a CurrentRow property to my listbox subclass and then in SelectionChanged, I save the prior row and set the current row. I don’t ask, because for my application, the user just expects their changes to be saved.

4 Likes

Not with reference to a Listbox, but in my Prefs, as soon as the user makes a change, that Prefs tab is marked as dirty and the OK/Cancel buttons change to Save/Revert. User can’t switch to another Prefs tab unless they Save or Revert.

Not understanding the meaning of Dirty in this context, but I like the idea of the user not able to continue before making a choice.

I was able to make the Update code work behind the screens by triggering it in the LostFocus event of the text fields. No need for the update button at all now.

There is an edge case where if the user changes the text field and then closes the window, LostFocus never happens. That’s why you need to maintain your own flag that says “I changed” and check it everywhere you need to, such as Window.Closing. You can loop through all the controls and save the ones that changed.

Thanks, good to know.
A strange issue cropped up just now that I never noticed before. When clicking twice on the same row in the Listbox, the connected text field and a calendar object change their values. They switch between 2 different values with every mouse click on the same Listbox row.

I don’t see any weird code in the Listbox Change Event. Any idea why this is happening?

Without seeing the code that loads those fields, it would be hard to guess.

What I see now this is happening: It switches between the original value of the field and the last added value from a record in the listbox.

And I wouldn’t expect Listbox Change event to be the culprit. Do you have code in CellClick or MouseDown?

No cellClick or MouseDown events on this Listbox, only a Change event.

This is the Change Event code from the Listbox:


TextFieldCharacterName.text = "" 

// grasp and show the Character ID in the CharacterID label
CharacterID.text = ListBoxCharacters.CellValueAt(ListBoxCharacters.SelectedRowIndex,1)
CharacterID_Selected = ListBoxCharacters.CellValueAt(ListBoxCharacters.SelectedRowIndex,1)
CharacterName_Selected =  ListBoxCharacters.CellValueAt(ListBoxCharacters.SelectedRowIndex,0)
SelectedQuestionCharacter.text = CharacterName_Selected
textCharNameChange.text = CharacterName_Selected

//Character is selected, so enable the fields, get data and display in fields
if ListBoxCharacters.SelectedRowIndex <> -1  then
  btnSaveChangesStoryTitle.enabled = true
  textCharNameChange.enabled = true
  btnDeleteCharacter.Enabled = true
  AddCharacter.Enabled = true
  AddCharacter.visible = true
  btnUpdateCharInfo.enabled = false
end if

if ListBoxCharacters.SelectedRowIndex = -1  then
  btnSaveChangesStoryTitle.enabled = false
  btnUpdateCharInfo.enabled = false
end if

//To populate popupmenu and all the other fields:
if ListBoxCharacters.SelectedRowIndex >= 0 then
  Var rs As RowSet
  Try
    rs = app.DB.SelectSQL("SELECT * FROM characters WHERE ID = ?", ListBoxCharacters.RowTagAt(ListBoxCharacters.SelectedRowIndex).StringValue)
  Catch e As DatabaseException
    MessageBox("Error loading data: " + e.Message)
    Return
    
  End Try
  
  If rs <> Nil Then
    txtCharacterInfo.Text = rs.Column("Character_Information").StringValue //Text field
    popArch.SelectRowWithValue(rs.Column("Character_Type").StringValue) //Popup menu
    PopupMenuGender.SelectRowWithValue(rs.Column("Character_Gender").StringValue) //Popup menu
    txtCharacter_Age.Text = rs.Column("Character_Age").StringValue //Text field
    DateofBirth.SelectedDate = rs.Column("Character_Date").DateTimeValue //Calendar birthdate
    txtCharQuestionsSum.Text = rs.Column("txtCharQuestionsSum").StringValue //Text field
    
    btnUpdateCharInfo.Enabled = false
  End If
  
  // close RowSet
  rs.Close
end if

The value switching happens with the txtCharacter_Age field and the DateofBirth DateTimePicker.

I wasn’t able to solve the problem but deleted the age text field and replaced it with a popup menu that contains age ranges instead. Looks better and the problem is gone now. Only the Calendar object is still acting weird. However because it already is very unpredictable in behaviour (the year cannot be entered correctly because it keeps on deleting the first 2 numbers), I deleted this object completely. So problem solved :slight_smile: