I am using 2 listviews and am copying items from one to another (using the code b开发者_开发百科elow) however when the onInsert event of the destination Listview is triggered the Item value passed is always nil rather than the newly moved list item, could someone please point out what I am doing wrong?
Source.Items.BeginUpdate;
Destination.Items.BeginUpdate;
for i := Source.Items.Count - 1 downto 0 do
if Source.Items[i].Selected then
begin
Destination.Items.Add.Assign(source.Items[i]);
Source.Items[i].Delete;
end;
Source.Items.EndUpdate;
Destination.Items.EndUpdate;
Thanks
Colin
I cannot duplicate OnInsert
being called with a nil
Item. Hence I presume you mean, when OnInsert
is called the Item parameter does not have the properties (caption, data, image index etc..) of the source item. The reason is, when 'OnInsert' is called, the assignment is not yet carried out.
This line
Destination.Items.Add.Assign(source.Items[i]);
is analogous to
var
Item: TListItem;
...
Item := Destination.Items.Add; // <- OnInsert is called here
Item.Assign(source.Items[i]);
The problem is that the Caption
(or any other interesting property) of the newly created TListItem
hasn't been set yet. It is somewhat of a mystery that the VCL offers this Item
parameter, because I have tried all imaginable ways of adding a new list item, but non of them result in any useful Item
parameter. The event was always called before the properties were set. Maybe you are only supposed to set the properties of this parameter, not read them.
I think you have to rethink the design. A workaround that might or might not work for you is to use the OnChange
event instead. Of course, this will fire not only when the item is first inserted, but anytime the item is changed.
procedure TForm1.DestinationChange(Sender: TObject; Item: TListItem;
Change: TItemChange);
begin
ShowMessage(Item.Caption);
end;
It might be a bit of a 'hack', but if you really want to mimic the scenario you would have had if the original approach had worked (that is, if the Item
parameter would have been fully initialized), you could do something like
var
tmpItem: TListItem = nil; // preferably this should
// be a private member of the form class instead
procedure TForm1.DestinationChange(Sender: TObject; Item: TListItem;
Change: TItemChange);
begin
if Assigned(Item) and (Item = tmpItem) then
begin
// Here you got the real item you just added
ShowMessage(Item.Caption);
tmpItem := nil;
end;
end;
procedure TForm1.DestinationInsert(Sender: TObject; Item: TListItem);
begin
tmpItem := Item;
end;
But if I were you, I'd definitely redesign. Hacks aren't good. (At least I wouldn't trust this hack.) After all, it is you who add the new items to Destination
, so why do you ask the TListView
to 'remind' you when the items are added? Indeed, you do it here:
Destination.Items.Add.Assign(source.Items[i]);
Here you add the source.Items[i]
list item into Destination
[strictly speaking, you create a new item in Destination
and then 'assign' it the properties of source.Items[i]
]. Anything you could do in OnInsert
, you can just as well do here, and here you got full access to the list item in question: it's simply source.Items[i]
. Do what you like with this data!
精彩评论