Reproduction: click the button to initialize the ListView, then select any item (except the first). The output in the Form caption will show that, having accessed TopItem, the value of Item has now been changed.
Can anyone explain this?
procedure TForm1.Button1Click(Sender: TObject);
begin
ListView1.OwnerData := True;
ListView1.Items.Count := 5;
end;
procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
begin
Item.Caption := '...';
end;
procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem;
Selected: Boolean);
var
one, two: string;
begin
if Item <> nil then
one := IntToStr(Item.Index)
else
one := 'nil';
if ListView1.TopItem <> nil then;
if Item <> nil then
two := IntToStr(Item.Index)
else
two := 'nil';
Form1.Caption := one + '/' + two;
end;
In non-virtual mode (
OwnerData=False), the ListView holds physical items, where every item is represented by a uniqueTListItemobject in memory. But, in virtual mode (OwnerData=True), the ListView has no physical items at all, so noTListItemobject is created for each item.However, since
TListViewexposes public interfaces that useTListItem, and those interfaces have to continue working even in virtual mode,TListViewholds 1 internalTListItemobject in virtual mode, which gets reused for any operation that involves aTListItem.So, in your example, when you select any list item, the
OnSelectItemevent is fired with aTListItemparameter, soTListViewhas to first fire itsOnDataevent to fill the internalTListItemwith data for the selected item. Then, when you access theTListView.TopItemproperty,TListViewhas to fire itsOnDataevent again to fill that same internalTListItemobject with new data for the top visible item.That is why you are seeing the
Item.Indexproperty change value.When using virtual mode, don't expect a given
TListItemto remain intact after you have accessed a differentTListItem. In fact, you should really avoid using anyTListItemoperations as much as possible. If you need to access information about a particular list item, and that information is not already available in your own data source, then you should query the underlyingListViewcontrol using the Win32 API directly, so as not to affect theTListView's soleTListItemobject, eg: