How to safely delete object referenced by listview?

I have a ListView widget in an EditorUtilityWidget.

The ListView has an EntryWidgetClass set to a widget with UserObjectListEntry interface, and the relevant functions and events are set up currently just to store and send the represented object.

In the EditorUtilityWidget, I Get All Level Actors, filter them by a class, and pass the resulting array into Set List Items called on the ListView.

This all works.

But, if I manually delete one of the objects in the world editor, the editor crashes on the error:

LogSlate: Warning: WidgetMapToItem length (6) does not match ItemsWithGeneratedWidgets length (5). This is often because the same item is in the list more than once in ListViewT<ItemType> [ListViewBase.h(219)]. Diagnostics follow.

The diagnostics that follow show what you’d expect, the 6 ItemToWidgetMap entries. The 6 WidgetMapToItem entries, and the 5 ItemsWithGeneratedWidgets entries (because I deleted one manually.)

So, I understand the problem here, but I don’t know how to resolve it.

I have tried:

  • Regenerating the ListView
    OnEntryReleased and also on the
    ListObjectWidget’s OnEntryReleased.
  • Regenerating the ListView on the
    object’s OnDestroyed and OnEndPlay
    events.
  • Calling Set Items on the ListView
    on the object’s OnDestroyed and
    OnEndPlay events.
  • There is also a tick event on the EditorUtilityWidget that reacts to a change in number of actors that is meant to refresh the panel, but includes the clearing and setting of this ListView… crashes before this happens.

I can’t seem to figure out what the engine wants me to do to intercept this event before Slate ends up with the mismatched item list.

I’m not sure what else I’ve tried- it’s hard to keep track and be methodical when I have to go through crash recovery processes every time I try something new.

Just trying to figure out the best practices for accounting for the manual deletion of an object that is referenced by a listview.

After some further testing and paring down the code to isolate the issue, I now find that…

If I detect that an actor has been deleted from the scene and perform the following steps:

  1. Call ClearListItems on the ListView
  2. Call GetAllLevelActors and FilterByClass to get (and confirm) an array of current list represented objects
  3. Foreach through the array of objects, calling AddItem to ListView
  4. Call RegenerateAllEntries on ListView

The editor still crashes, but now WidgetMapToItem and ItemsWithGeneratedWidgets show proper contents, but ItemToWidgetMap has one phantom Item (presumably for the deleted object) mapped to a duplicate WidgetMap.

(This also happens if I replace step 3 with a call to SetListItems on the ListView.)

Ok, after further testing and combing through source code…

There seems to be something about the way level actors are stored in memory even after deletion that causes the ItemToWidgetMap to retain a reference to a deleted actor.

I have solved this issue by using a proxy data object to stand in for the actor when populating the list. The object contains a reference to its actor. When the object is passed into the ListView as an item, during the EventOnListItemObjectSet the actor is passed into the widget for populating informational child widgets. This lets me keep all the important data on the actor itself… the data object just sort of acts as a handshake.

I’ve been suffering with this problem on occasion. I noticed I would get the same crash when compiling a BP that I was using as a item in the listview.

Your post was helpful! I ended up doing the same thing. Generating a wrapper for the actors that would show up in the listview. Now when I recompile the actors, no crash, because the actor is no longer the “Item” the widget is generated for. The wrapper is.