Search Unity

ListView childCount always zero?

Discussion in 'UI Toolkit' started by Alex-Chouls, May 11, 2022.

  1. Alex-Chouls

    Alex-Chouls

    Joined:
    Mar 24, 2009
    Posts:
    2,663
    I'm trying to iterate over the children of a ListView, but childCount always returns 0.

    I thought I must be doing something wrong, but even in the Binding example, if I add a callback and log childCount it always returns 0.

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using UnityEngine.UIElements;
    4.  
    5. namespace UIToolkitExamples
    6. {
    7.     [CustomEditor(typeof(GameSwitchListAsset))]
    8.     public class GameSwitchListEditor : Editor
    9.     {
    10.         [SerializeField]
    11.         VisualTreeAsset m_ItemAsset;
    12.  
    13.         [SerializeField]
    14.         VisualTreeAsset m_EditorAsset;
    15.  
    16.         private ListView _listView;
    17.        
    18.         public override VisualElement CreateInspectorGUI()
    19.         {
    20.             var root = m_EditorAsset.CloneTree();
    21.             _listView = root.Q<ListView>();
    22.             _listView.makeItem = m_ItemAsset.CloneTree;
    23.            
    24.             _listView.RegisterCallback<DragUpdatedEvent>(OnDragUpdated);
    25.            
    26.             return root;
    27.         }
    28.  
    29.         private void OnDragUpdated(DragUpdatedEvent evt)
    30.         {
    31.             Debug.Log(_listView.childCount);
    32.         }
    33.     }
    34. }
    Drag an asset over the list view to test. Unity 2021.2.15f

    What am I doing wrong?
     
  2. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    childCount is not a property of ListView; it's a property of VisualElement that returns the number of children in its contentContainer. The contentContainer of a ListView is set to null to avoid users adding and removing elements from it, as it manages its own content with lots of tricks for performance. Even if you could get a childCount, it may not be what you expect; e.g. you could get some pooled elements that aren't visible or bound.

    If you really want to circumvent that, you could try Hierarchy.childCount.
     
  3. Alex-Chouls

    Alex-Chouls

    Joined:
    Mar 24, 2009
    Posts:
    2,663
    What's the recommended way to iterate through the visible items in a ListView? I'm trying to implement drag and drop from outside the ListView. Or is there another way to set that up? Seems like a common use case.
     
  4. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    I don't know if there's a recommended way. If you want to be able to drop things between list items, I'd suggest creating custom list elements and listening for DragAndDrop events inside each of them, that way you'd know where the item was dropped. You may need to do your own binding of the elements too, though, because binding the whole list sometimes doesn't play well with custom item-making delegates. If you don't care about inserting items, you could just detect DragAndDrop from the ListView's parent.

    To be honest, ListView is pretty awesome, specially for performance with large lists, but for really custom editor stuff like that I've come to prefer my own custom Element. It's turned out to be easier and more stable for those kinds of cases. Here is the class I use for most of these cases if you want to look. I'd normally create a child class, and then override the
    VerifyCustomDrag
    and
    OnCustomDragPerformed
    methods from the parent class. If you plan to use it directly, right now I'd suggest using the development branch because it has lots of commits that I haven't had time to bring to the main one.

    EDIT
    I'm thinking that, if you don't want to do your own custom iterating with the hierarchy property, you may be able to iterate the ListView's elements by querying it for items with the itemUssClassName. You'd then have to get the actual item's index from your element; you can't trust the items' place in the hierarchy because they are in a virtualized Scroll View. Querying may also get a bit complex if you have nested lists.
     
    Last edited: May 12, 2022
    Alex-Chouls likes this.
  5. Alex-Chouls

    Alex-Chouls

    Joined:
    Mar 24, 2009
    Posts:
    2,663
    Thanks! I just realized I've been studying your work - UITKEditorAid has been incredibly helpful reference for figuring out UIToolkit! I've had my list views setup with ListControl, and also with ListView and DragAndDrop events on individual items, but thought that might not be so good performance-wise with large lists. So I was actually trying to do what you do with GetDropIndex in ListControl with a ListView.

    I'm trying to do as much as possible with built-in UIToolkit controls, to inherit bug fixes, performance improvements etc. and also to just write the absolute minimum amount of code to do the job. After maintaining PlayMaker editor code for more than 10 years across multiple versions of Unity, I've seen just how much work custom code and workarounds can create! So minimal code is like a religion for me now! And I love how minimal the code for a bound ListView is. However, I keep running into bugs, especially working with SerializeReference lists, so... maybe it's back to ListControl :)
     
  6. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    No problem. Yeah! I agree with you. I also try to use Unity's elements as much as possible. I find that sometimes reducing the complexity of custom code is tricky with UIToolkit, because things are so easy to change and extend. Sometimes I find myself doing a lot more custom code to bend some VisualElement from Unity, than what it would have been to just making my own implementation.

    Also, it's easy to depend on stuff that's really implementation details, because a lot is accessible through the hierarchy, event propagation and all kinds of interfaces susceptible to implementation variations. I've found that the less I bend Unity's elements, the fewer things break when there are changes.

    EDIT
    I've found that UIToolkit has problems reacting to SerializeReference fields changing types, which occurs frequently in reorderable lists. I've made an element to fix that too. It seems my fix might not be needed in 2022 versions, as they do track those kinds of changes; I've still found a couple of issues and some crashes in those versions, but hopefully they'll be fixed.
     
    Last edited: May 12, 2022
    Alex-Chouls likes this.
  7. Alex-Chouls

    Alex-Chouls

    Joined:
    Mar 24, 2009
    Posts:
    2,663
    Thanks for the ManagedReferenceField link - you are a hero! Also for the tip to use the development branch. I had noticed that EditableLabel wasn't working in 2021.2, and it looks like that's fixed in development.

    Do you have any plans to support multi-select in ListControl?
     
  8. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    :) No problem. I'm glad if it helps.

    Multiselect is something I want to add, and it's not too complicated, but it'd require changing some public members, so I've been leaving it for later. To be honest, it's not something I'll probably add soon, but PRs are more than welcome .