开发者

Delphi Listview onInsert Problem

开发者 https://www.devze.com 2023-03-11 08:03 出处:网络
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

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!

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号