I have a listbox on a form next to a Page Control with datafields displayed to the right for the selected record.
The listbox contains 1 column with a member Name in the Lastname, Firstname format (as one field)
There is a textfield above the listbox where the user can start typing the first few characters of the last name of the desired member.
On the KeyUp event I reload the listbox from a RecordSet built from a select:
sFilter = sStart + "%"
sSQL = "SELECT * FROM Members WHERE LastName LIKE '" + sFilter + "' ORDER By LastName"
Where sStart is the field containing the characters typed in by the user, e.g. “plu” would create an sFilter of “plu%”
When the user double-clicks a row in the listbox, the member clicked is displayed in the data fields. The code in the double-click event of the listbox is:
dim iRow As Integer
dim iRecID As Integer
iRow = Me.ListIndex
iRecID = Me.RowTag(iRow)
GetMemberObject(iRecID)
LoadRS("ALL")
PopulateMembersLB
me.selected(iRow) = true
tfLastNameSearch.Text = ""
return
This all works perfectly but I included it for context.
After this double-click event is processed and the selected record displayed, I clear the textfield where the 1st characters of last name are typed.
Reload the listbox with ALL records again.
But now the problem. I want the row the user double-clicked to be selected and within the view of the displayed listbox.
The 1st problem is the statement lbMembers.selected(iRow) = true does not cause the clicked row to be highlighted (selected?)
The 2nd problem is how do I cause the listbox to scroll to the selected record - that is after I can get it to be selected?
I am having a similar problem and would like some guidance.
I have a listbox that is populated in a separate method from a database. If I change any data items (using the listbox editing) I update the record in the database and reload the listbox. I then want the originally selected (and modified) record line in the listbox to be selected and within view.
I store the database table key in the row tag property, and the reload of the table data updates the listbox lines accordingly.
I then set up a loop from 0 to listcount-1 and check the row tag value at each iteration. If it matches the changed record’s key then I set the listindex to the loop counter and exit.
Code snippet here:
[code]Dim row As Integer = -1
For lp As Integer = 0 To lbA.ListCount - 1
If lbA.RowTag(lp) = ac.mKey Then
row = lp
Exit For
End If
Next
If row <> -1 Then
lbA.ScrollPosition = row
lbA.ListIndex = row
End If
[/code]
My issue is that this just has no effect. I have tried it with commenting out both the scrollpostion and listindex lines individually.
I have traced the program under debug and gone through the whole loop process and viewing the listbox in the debugger. This shows that the listindex is being set to the correct value - but - when the listbox is actually displayed the selected row is not being shown.
This is particularly annoying when the edited field is part of the order by clause of the sql and its position in the listbox now changes.
If row <> -1 Then
lbA.ScrollPosition = row <- you scroll to the row
lbA.ListIndex = row <- you say which row is the selected one (ListIndex is a property of ListBox)
lbA.Selected( row ) = TRUE <- this line actually sets the row to selected, so without it your code won't work the way you think it does
End If
[code]If row <> -1 Then
lbA.ScrollPosition = row ← you scroll to the row
lbA.ListIndex = row ← you say which row is the selected one (ListIndex is a property of ListBox)
No. Here I set the listbox index to the one I want.
lbA.Selected( row ) = TRUE ← this line actually sets the row to selected, so without it your code won’t work the way you think it does
End If[/code]
Normally, setting the listbox list index to a value selects it and highlights it. Unfortunately this is not happening for me.
I can’t create a simple project as these lines are within a class I have created that inherits from listbox. I just don’t understand why any of the normal things work.
I think it has to do with what happens internally to listbox. My class reacts to a click on a cell, opens the edit and allows an edit. In the subsequent Cell Action method I RaiseEvent for my child listbox to react with the program. My issue is within this raised event in the child where I am attempting to highlight the changed row. I think something else must happen in the base class after the CellAction has been called. The ListIndex and Selected properties have to be recharged within the parent Listbox - I don’t do anything with them after the CellAction call.
The documentation indicates that ListIndex is a writable property. Also from the doc page “The selected item number. The index is zero-based.” So, with the property being writable and this description, only a small leap of ingenuity needs to be made. I tend to use Listbox.ListIndex = x to set a listbox selection, and haven’t had an issue with it (yet!)
This can happen if you’re changing the selection during a Listbox event. A quick’n’dirty fix is to use a timer to make a delay, but this can be the start of unpredictable behaviors.
[quote=352377:@Markus Winter]If you select a row then the number of the row is saved in the ListBox.ListIndex property.
[/quote]
Markus,
After all these years I a bit surprised at your post and understanding on how listboxes work.
What you wrote is a bit misleading… That is only true when you only allow a single selection in the listbox.
But a listbox can be set to have more than one row selected at a time. In fact it is for that usage that there IS a selected method. For single selection listboxes, ListIndex alone suffices and is what should be used.
For multi-selection listboxes the listIndex is set the the first (lowest row index) selected row in the listbox, and changing it will deselect all previously selected rows and select the one specified (unless it is set to -1. In that case no row is selected)
As I am attempting to set the list index to a new one within an instance of a sub-classed ListBox of my own then the root Listbox class is obviously still doing something after the end of my raised event.
I think I will explore the Timer suggestion.
Markus, thanks for the help and suggestions so far but I have always used the lb.ListIndex = myrow to set the selection. It just isn’t working in this instance!
Over the years I have created many sub-classed list boxes to do various common tasks (see my website Simcar Software) and I have noticed this behaviour before. I have never found a solution and found workarounds. However, in my current project I really need to set the selected rows correctly and I have been agonising over this for a long time!
[quote=352432:@Simon Berridge] This can happen if you’re changing the selection during a Listbox event. A quick’n’dirty fix is to use a timer to make a delay, but this can be the start of unpredictable behaviors.
This, I think, is where my problem lies.[/quote]
That can only happen if you as a developer already use a timer (might be combined with a thread) to load data into the listbox. “changing the selection during a Listbox event” is not possible without a timer. Events are fully processed before any other function or method of the application is executed.
Eli, this is not the case. I don’t use a timer at all in my listbox class. I have now tried the following:
I created a new timer class called slbResetRow.
Constructor:
Public Sub Constructor()
Period = 500 ' 1/2 second
Mode = Timer.ModeOff
End Sub
Action:
Sub Action() Handles Action
System.DebugLog "In the timer Action."
LBox.ListIndex = RowID
System.DebugLog "Executed the timer."
End Sub
Properties:
Public Property LBox as Listbox
Public Property RowID as Integer
In my raised event of the listbox (sub-classed from ListBox) on my window I have the following code:
For lp As Integer = 0 To me.ListCount - 1
If Me.RowTag(lp) = ac.mKey Then
System.DebugLog "Setting up timer."
System.DebugLog "Current List Index : " + Str(me.listindex)
System.DebugLog "New List Index : " + Str(lp)
Dim tmr As New slbResetRow
tmr.LBox = Me
tmr.RowID = lp
tmr.Mode = timer.ModeSingle
tmr.Enabled = True
' Me.listindex = lp
' Me.Selected(lp) = True
Exit For
End If
Next
Running my app the listbox is not updated. Looking at the debug log after execution I can see that the Action event of the timer is never called! I get the first three lines (“Setting up timer”, "Current List Index : " and "New List Index : ") but the log never shows “In the timer Action.” or “Executed the timer.”.
[quote=352444:@Simon Berridge]@Eli Ott … already use a timer …
Eli, this is not the case. I don’t use a timer at all in my listbox class. I have now tried the following:
I created a new timer class called slbResetRow.
[/quote]
What I meant is, if you did not use a timer, then it is not possible that an event (like click or so) interrupts another event, as you suspected further above. There is no need to introduce a timer.
I have the same setup as you both and never did encounter that problem. After reloading data to the listbox, just walk over it and use ListIndex to select the correct row (by comparing to rowId in RowTag). Do not forget to first empty the listbox (this happened to me once).