DesktopListbox: Modifying or Rejecting a Cell Edit

Hi all,

I have a listbox with some cells of type DesktopListbox.CellTypes.TextField.

These cells are user-editable, but I want to validate the entries and either reformat them or reject the edit outright.

To do this, I have saved the cell’s original value in the .CellTagAt property.

However, in the CellTextChange event, if I try to change the CellTextAt(Row, Column) property and change the text of the cell, the change has no effect.

I think this is because my cell change is happening behind the .ActiveTextControl, which doesn’t know anything about my new .CellTextAt and overwrites it as soon as the edit is finished.

Trying to change the text in Me.ActiveTextControl.Text causes a stack overflow (because changing the text in that event triggers a new TextChanged event on itself).

Here’s a sample project illustrating the issue: Dropbox - listbox reject edits.xojo_binary_project - Simplify your life

Given there’s no event for when a cell’s edit is complete, what’s the best way to validate and modify a user’s edit in a listbox cell?

This is a common dilimma of How do I change a TextField in code without triggering an event. You don’t. The solution is to set a flag ChangingViaCode before you update the textfield and clear it after. In the TextChanged event, check the flag and return if true, otherwise, process the change.

I got intrigued by this and I have slapped together a basic solution that will get you started in the right direction.

Delete your entire approach and start with a fresh Listbox. :slight_smile: Add the DoublePressed event:

Sub DoublePressed() Handles DoublePressed
  'What row did the user double-click?
  lastEditRow=me.SelectedRowIndex
  
  'Save the content for future rollback
  lastPreEditContent=me.CellTextAt(lastEditRow, 0)
  
  'Start editing the row text
  me.EditCellAt(lastEditRow, 0)
  
  'Attach a handler to the text edit control's Focus Lost event
  AddHandler me.ActiveTextControl.FocusLost, addressof self.ListboxEditFinished
End Sub

Add this method to the window:

Public Sub ListboxEditFinished(theTextControl as DesktopTextControl)
  'Do whatever validation/rollback/etc is necessary here
  'Save the value to the control, because whatever is in that control will be sent to the listbox
  theTextControl.Text=lastPreEditContent
End Sub

Add two properties to the window:

lastEditRow as integer
lastPreEditContent as string

Basically, you’re attaching an event handler to the internal text edit field and catching its FocusLost event - which is fired when editing is finished. Then, you do whatever manipulations you need to the edit field’s text directly, and the Listbox will grab that text and put it in place.

1 Like

If you can, move your code to KeyDown.

The problem is that you don’t get events for that via the Listbox. All you get is the equivalent of a TextChanged event.

One way I set properties on the ActiveTextControl is in the CellFocusReceived event. You should be able to manage this that way. IIRC, CellAction is raised when a change is committed, so you could validate there.

1 Like

This is a really interesting approach, thanks for this. There are a few challenges.

A field can be edited without a double-click. A single click on the currently selected row will also initiate an edit without firing the MouseDown/MouseUp events for the Listbox.

An edit can also be completed without triggering the ActiveTextControl’s FocusLost event, if the user presses Return. Only if they click another row does FocusLost fire.

I’d love it if the Listbox would have an event like EditCellAboutToBegin, where you could return a custom subclass of DesktopTextControl that could manage the editing process, instead of wiring it up during runtime using AddHandler. This would be a much cleaner, more flexible approach.

2 Likes

Make sure you’re not setting the cells to be editable. You should only be editing via the DoublePressed event.

This is the event I was looking for, thank you Anthony! In CellAction I can check the new value against the saved value in the celltag and validate accordingly.

Cheers everyone, appreciate all the help.

1 Like

Shouldn’t this trigger the FocusLost event anyway? The focus gets lost when one presses Return.

I’d expect the cells to show a sign of being editable when it is (like an I-Beam cursor showing when the mouse hovers the cell).

But setting the cell type to editable doesn’t do that until you’ve double-clicked to edit it, which is the game behavior as my solution.

Hello, I use cellpressed for my listbox selection
Red fields are locked - approval required
Other fields can be reached using the arrow keys
Examble:

https://www.dropbox.com/scl/fi/xhyitwc79mk8c80vnrfhh/Listbox-edit-test.xojo_binary_project?rlkey=at6ckp9niapzzz23m0b4lz2q1&dl=1

1 Like

The issue with requiring double-clicks to edit a listbox cell is that it breaks the UI guidelines for touchscreens on Windows.

This is a really cool example and an interesting way to do it! Thanks for sharing.