Reputation: 27276
I'm using a TListView
in Firemonkey. On startup, I create 3 list view headers and keep references to them for future use (specifically inserting items below each header).
FItemHeader:= LV.Items.Add;
FItemHeader.Purpose:= TListItemPurpose.Header;
FItemHeader.Text:= 'Items';
FChargeHeader:= LV.Items.Add;
FChargeHeader.Purpose:= TListItemPurpose.Header;
FChargeHeader.Text:= 'Charges';
FPaymentHeader:= LV.Items.Add;
FPaymentHeader.Purpose:= TListItemPurpose.Header;
FPaymentHeader.Text:= 'Payments';
Then, I've added a few items below the first (Item) header, which works fine.
SomeItem:= LV.Items.Insert(FChargeHeader.Index);
Then later, I wish to insert an item below one of the other headers...
SomeItem:= LV.Items.Insert(FPaymentHeader.Index);
This is supposed to add the item just above the Payments Header (last item in the Charges section). However, it instead gets added further up the list (at index 2).
While debugging this issue, it came as a surprise that the 3 headers' indexes have not been updated after adding items. The following code demonstrated that:
S:= 'Items: '+IntToStr(FItemHeader.Index)+sLineBreak+
'Charges: '+IntToStr(FChargeHeader.Index)+sLineBreak+
'Payments: '+IntToStr(FPaymentHeader.Index);
ShowMessage(S);
The indexes were 0
, 1
, and 2
even though they're supposed to be larger (after adding some items).
Further debugging led me to add this code:
for X := 0 to LV.Items.Count-1 do begin
S:= S + LV.Items[X].Text+' - '+IntToStr(LV.Items[X].Index)+sLineBreak;
end;
ShowMessage(S);
Which reports all the correct indexes. Further, if I call this second piece of code and then the first piece, the indexes are fine..
for X := 0 to LV.Items.Count-1 do begin
S:= S + LV.Items[X].Text+' - '+IntToStr(LV.Items[X].Index)+sLineBreak;
end;
ShowMessage(S);
S:= 'Items: '+IntToStr(FItemHeader.Index)+sLineBreak+
'Charges: '+IntToStr(FChargeHeader.Index)+sLineBreak+
'Payments: '+IntToStr(FPaymentHeader.Index);
ShowMessage(S);
So after a bit more digging, it turns out a simple call to...
LV.Items[1].Index;
...forced that particular item to be re-indexed.
While technically this works, it's an extremely sloppy work-around. What else can I do to ensure this list view gets re-indexed prior to inserting an item?
NOTE: When I did a similar approach using a TListBox
I did not have this issue. It's surely a bug in the TListView
control. I'm not asking how to fix the bug, but for a better work-around.
NOTE: This work-around only appeared to work once or twice - further attempts and even this work-around doesn't force a re-index.
UPDATE
It seems that this is the only magical work-around, which is still very sloppy:
procedure ReindexListView(AListView: TListView);
var
X: Integer;
begin
for X := 0 to AListView.Items.Count-1 do
AListView.Items[X].Index;
end;
Upvotes: 1
Views: 1727
Reputation: 27276
While the real fix is in Embarcadero's ball court, this seems to be the only work-around:
procedure ReindexListView(AListView: TListView);
var
X: Integer;
begin
for X := 0 to AListView.Items.Count-1 do
AListView.Items[X].Index;
end;
Behind the scenes, there is a known bug in the generic TList
implementation, specifically a mis-hap with the Insert
function. I haven't confirmed whether this is the case or not, but this work-around does the trick at least.
Upvotes: 0
Reputation: 2940
This is bug in Delphi XE8. Works fine in Delphi XE7 Update 1.
Read more about bug: Delphi XE8 bug in TList<T>, need workaround
Really looks like a bug. Tested with Delphi XE8 under Win32 and Win64.
Method .AddItem
has the same effect like .Insert
How it looks:
How it should be (and how it looks if you are using LV.Items[1].Index
). NOTE: The same effect if prior adding item under "Charges" you going to select any item in TListView
Upvotes: 1