Jump to content
Marsil

Why TListView.OnItemChecked event called by ListView.Items.Add?

Recommended Posts

Hi,

 

I have  a ListView with CheckBoxes enabled (CheckBoxes = True) and an OnItemChecked event handler,

if I try to add an item to the ListView:

 

var Item := ListView1.Items.Add;   // this immediately triggers OnItemChecked 
Item.Data := SomeLinkedObject;
Item.Checked := SomeLinkedObject.Enabled;

the  OnItemChecked event handler is called immediatley not giving me a chance to assign the

Item.Data property.

 

The handler is

procedure TForm1.ListView1ItemChecked(Sender: TObject; Item: TListItem);
begin
  if not Assigned (Item.Data) then
     Memo1.Lines.Add ('ListView1ItemChecked called with nil Data ');   // this debug always executed with nil data 
  TSomeLinkedObject (Item.Data).Enabled := Item.Checked  // AV here when ListView1.Items.Add executed
end;

 

Any idea why this is happening? or is it a bug?

Edited by Marsil

Share this post


Link to post

The checkboxes are implemented as state images. You are getting the event when the item's initial state is assigned.  Just check for the nil condition and don't access the object when it's not ready yet:

procedure TForm1.ListView1ItemChecked(Sender: TObject; Item: TListItem);
begin
  if Assigned(Item.Data) then
    TSomeLinkedObject(Item.Data).Enabled := Item.Checked;
end;

Alternatively, disable the event when adding an item, and then re-enable the event when ready:

ListView1.OnItemChecked := nil;
var Item := ListView1.Items.Add;
...
ListView1.OnItemChecked := ListView1ItemChecked;
Edited by Remy Lebeau
  • Thanks 1

Share this post


Link to post

Thanks Remy, I implemented the first workaround.

 

But I still don't understand why the ListView is firing the checked event for an item that still being created and still not properly initialized yet?😕

this behavior was really unexpected :classic_unsure:

 

I always use VirtualTreeView, but this time I decided to use ListView because it will only contain just one or two items, a quick lightweight  job.

 

Share this post


Link to post
38 minutes ago, Marsil said:

that still being created and still not properly initialized yet?

But, it is already created, initialized (with default) and added with 

ListView1.Items.Add

Your next 

Item.Checked := SomeLinkedObject.Enabled;

Is triggering the event as designed, nothing wrong here, 

 

If you don't want that behavior, then try to create the item as local var, not by calling Items.Add then set (Initialize) properties and only then add it to the items, though i am not sure if this will trigger the event or not, it shouldn't, but who knows you need to test it, this will change the narrative of the expected behaviour and might, i say might, be discussed as bug or short in design, if just adding an item triggers an event.

  • Thanks 1

Share this post


Link to post
23 minutes ago, Kas Ob. said:

But, it is already created, initialized (with default) and added with 


ListView1.Items.Add

I mean my own initialization!

 

23 minutes ago, Kas Ob. said:

Your next 


Item.Checked := SomeLinkedObject.Enabled;

Is triggering the event as designed, nothing wrong here, 

 

No, the OnItemChecked event is triggered by this statement

var Item := ListView1.Items.Add;   // this immediately triggers OnItemChecked 

As I explained in the comment, I tried and removed the 

Item.Checked := SomeLinkedObject.Enabled;

and same problem!!

 

23 minutes ago, Kas Ob. said:

If you don't want that behavior, then try to create the item as local var, not by calling Items.Add then set (Initialize) properties and only then add it to the items, though i am not sure if this will trigger the event or not, it shouldn't, but who knows you need to test it, this will change the narrative of the expected behaviour and might, i say might, be discussed as bug or short in design, if just adding an item triggers an event.

 

Thanks!, I will try what you suggested here!

 

 

Edited by Marsil

Share this post


Link to post
50 minutes ago, Kas Ob. said:

If you don't want that behavior, then try to create the item as local var, not by calling Items.Add then set (Initialize) properties and only then add it to the items, though i am not sure if this will trigger the event or not, it shouldn't, but who knows you need to test it, this will change the narrative of the expected behaviour and might, i say might, be discussed as bug or short in design, if just adding an item triggers an event.

 

I tried this

var Item := TListItem.Create (ListView1.Items);
Item.Caption := SomeLinkedObject.Name;
Item.Checked := SomeLinkedObject.Enabled;
Item.Data := SomeLinkedObject;
ListView1.Items.AddItem (Item);

but the item is shown without caption!, and memory leak occurred!

---------------------------
Unexpected Memory Leak
---------------------------
An unexpected memory leak has occurred. The unexpected small block leaks are:

13 - 20 bytes: TList x 4, Unknown x 4
21 - 28 bytes: UnicodeString x 3
37 - 44 bytes: UnicodeString x 1
45 - 52 bytes: TListItem x 4
77 - 84 bytes: TSubItems x 4

 

I don't think solves the issue since the only way to implement your suggestion is to use ListView.Items.AddItem which is called by ListView.Items.Add.

 

  • Like 1

Share this post


Link to post

You are right the the behavior is wrong and buggy, 

 

Using similar approach of create then add, doesn't show caption, but no memory leak on XE8.

Share this post


Link to post

Debugging and tracking the OnChecked event, the behavior has nothing to do with Delphi and its VCL, it is triggered by Windows message, so you have to use a workaround about that, something like what Remy suggested.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×