Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

About UIElements.ListView's API

Discussion in 'UI Toolkit' started by gh-peng, Feb 6, 2020.

  1. gh-peng

    gh-peng

    Joined:
    Dec 11, 2018
    Posts:
    2
    When I want use the control ListView, I found the function 'makeItem' which cann't make different VisualElement by the different item. If add a argument(the item's index) to function 'makeItem', then we can show different VisualElement according to the different item. I looked at the source code of ListView, the chage is very simple, but ListView will have more pow :). Does anyone agree with me? Thanks.
     
    Kan15hkSMT likes this.
  2. pirho_luke

    pirho_luke

    Joined:
    Oct 24, 2017
    Posts:
    21
    This is what the "bindItem" callback is for. This exists because ListView is virtualized, meaning it only creates a small subset of VisualElements for what is visible. Then as the list scrolls and changes, it will call "bindItem" for each VisualElement that is now visible. The idea is that in the makeItem callback you create the basic hierarchy of an item and then in the bindItem callback you fill each element with the appropriate data. Because the bindItem callback takes an int of the index in the list (like you are looking for), you should be able to use that to create the correct UI.

    Unity devs, correct me if I'm wrong!
     
  3. pirho_luke

    pirho_luke

    Joined:
    Oct 24, 2017
    Posts:
    21
  4. gh-peng

    gh-peng

    Joined:
    Dec 11, 2018
    Posts:
    2
  5. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,184
    There's also nothing stopping us from adding and removing sub-elements in the bind callback. I recently wanted to show a list of rows in which each row contains a label and a number of icons. The number of icons was unknown at design time, so instead of adding a fixed amount in UXML or in the makeItem callback, I cleared the child elements during bindItem and added as many icons as I needed. I haven't found any drawbacks to this approach, although one must pay attention to not create unwanted instances this way.
     
  6. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,203
    Creating/removing elements at bindItem() time is definitely a valid approach. We use it internally all lot. The only thing to watch out for is that you need to make sure to clean up potential hierarchy changes on your item every time you bindItem(). In the extreme case, that may just mean calling Clear() every time but ideally some optimization is used. New API of ListView will have an unbindItem() callback that you'll be able to use to clean up the item more...cleanly.
     
    kayy, Xarbrough and Ryuuguu like this.
  7. aybe

    aybe

    Joined:
    Feb 20, 2019
    Posts:
    53
    Why on earth does bindItem gets called with an out of bounds index in the original collection ?

    Code (CSharp):
    1. ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
    2. Parameter name: index
    3. System.ThrowHelper.ThrowArgumentOutOfRangeException (System.ExceptionArgument argument, System.ExceptionResource resource) (at <695d1cc93cca45069c528c15c9fdd749>:0)
    4. System.ThrowHelper.ThrowArgumentOutOfRangeException () (at <695d1cc93cca45069c528c15c9fdd749>:0)
    5. System.Collections.Generic.List`1[T].get_Item (System.Int32 index) (at <695d1cc93cca45069c528c15c9fdd749>:0)
    6. Rijji.Editor.Importers.RimEditorWindow.<CreateGUI>b__4_5 (UnityEngine.UIElements.VisualElement element, System.Int32 index) (at Assets/Scripts/Rijji/Editor/Importers/RimEditorWindow.cs:58)
    7. UnityEngine.UIElements.ListView.Setup (UnityEngine.UIElements.ListView+RecycledItem recycledItem, System.Int32 newIndex) (at Library/PackageCache/com.unity.ui@1.0.0-preview.14/Core/Controls/ListView.cs:1618)
    8. UnityEngine.UIElements.ListView.ResizeHeight (System.Single height) (at Library/PackageCache/com.unity.ui@1.0.0-preview.14/Core/Controls/ListView.cs:1573)
    9. UnityEngine.UIElements.ListView.Refresh () (at Library/PackageCache/com.unity.ui@1.0.0-preview.14/Core/Controls/ListView.cs:1516)
    10. UnityEditor.UIElements.Bindings.ListViewSerializedObjectBinding.UpdateArraySize () (at Library/PackageCache/com.unity.ui@1.0.0-preview.14/Editor/Bindings/ListViewBindings.cs:113)
    11. UnityEditor.UIElements.Bindings.ListViewSerializedObjectBinding.Update () (at Library/PackageCache/com.unity.ui@1.0.0-preview.14/Editor/Bindings/ListViewBindings.cs:160)
    12. UnityEngine.UIElements.VisualTreeBindingsUpdater.UpdateBindings () (at Library/PackageCache/com.unity.ui@1.0.0-preview.14/Core/Bindings/VisualTreeBindingsUpdater.cs:330)
    13. UnityEngine.UIElements.VisualTreeBindingsUpdater.Update () (at Library/PackageCache/com.unity.ui@1.0.0-preview.14/Core/Bindings/VisualTreeBindingsUpdater.cs:293)
    14. UnityEngine.UIElements.VisualTreeUpdater.UpdateVisualTreePhase (UnityEngine.UIElements.VisualTreeUpdatePhase phase) (at Library/PackageCache/com.unity.ui@1.0.0-preview.14/Core/VisualTreeUpdater.cs:155)
    15. UnityEngine.UIElements.Panel.UpdateBindings () (at Library/PackageCache/com.unity.ui@1.0.0-preview.14/Core/Panel.cs:926)
    16. UnityEngine.UIElements.UIElementsUtility.UnityEngine.UIElements.IUIElementsUtility.UpdateSchedulers () (at Library/PackageCache/com.unity.ui@1.0.0-preview.14/Core/UIElementsUtility.cs:259)
    17. UnityEngine.UIElements.UIEventRegistration.UpdateSchedulers () (at Library/PackageCache/com.unity.ui@1.0.0-preview.14/Core/UIElementsUtility.cs:105)
    18. UnityEditor.RetainedMode.UpdateSchedulers () (at Library/PackageCache/com.unity.ui@1.0.0-preview.14/Editor/RetainedMode.cs:41)
    19.  
    Right now the working fix is simply to ignore these wrong indices but still... why does Unity tries to access an out of bounds item in the list being bound?
     
  8. aybe

    aybe

    Joined:
    Feb 20, 2019
    Posts:
    53
    After digging a bit on the call stack, here's the bug:

    Code (CSharp):
    1.  
    2. In ListViewSerializedObjctBinding.SetBinding:
    3.  
    4. m_DataList = new SerializedObjectList(prop, listView.showBoundCollectionSize)
    When you set showBoundCollectionSize to false (which by the way doesn't work at all) the bug is gone!

    Somehow, Unity thinks the list has one element when showBoundCollectionSize is true while it's empty...
     
  9. aybe

    aybe

    Joined:
    Feb 20, 2019
    Posts:
    53
    And while I'm on it, onSelectionChange is broken, why does it gets raised when item is already selected ?

    The fix is to track its last value and return early when it hasn't changed ... the ListView should do that for us.

    In short, it is acting like an onMouseLeftButtonDown rather than a onSelectionChange.

    Thank you :)
     
  10. aybe

    aybe

    Joined:
    Feb 20, 2019
    Posts:
    53
    @uDamian

    Here's another good one:
    • create a list with a few elements
    • reorder the first element very slowly to the top, boom! exceptions all the way
    • list is then in a poor state with lots of empty elements
    • also, bindItem receives all sort of funny out of bounds indices
    Exception 1:

    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. UnityEngine.UIElements.ListViewDragger.ApplyDragAndDropUI (UnityEngine.UIElements.ListViewDragger+DragPosition dragPosition) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    3. UnityEngine.UIElements.ListViewDragger.UpdateDrag (UnityEngine.Vector3 pointerPosition) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    4. UnityEngine.UIElements.DragEventsProcessor.OnDragUpdate (UnityEngine.UIElements.DragUpdatedEvent evt) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    5. UnityEngine.UIElements.EventCallbackFunctor`1[TEventType].Invoke (UnityEngine.UIElements.EventBase evt) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    6. UnityEngine.UIElements.EventCallbackRegistry.InvokeCallbacks (UnityEngine.UIElements.EventBase evt) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    7. UnityEngine.UIElements.CallbackEventHandler.HandleEvent (UnityEngine.UIElements.EventBase evt) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    8. UnityEngine.UIElements.EventDispatchUtilities.PropagateEvent (UnityEngine.UIElements.EventBase evt) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    9. UnityEngine.UIElements.MouseEventDispatchingStrategy.SendEventToRegularTarget (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.BaseVisualElementPanel panel) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    10. UnityEngine.UIElements.MouseEventDispatchingStrategy.SendEventToTarget (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.BaseVisualElementPanel panel) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    11. UnityEngine.UIElements.MouseEventDispatchingStrategy.DispatchEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel iPanel) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    12. UnityEngine.UIElements.EventDispatcher.ApplyDispatchingStrategies (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel, System.Boolean imguiEventIsInitiallyUsed) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    13. UnityEngine.UIElements.EventDispatcher.ProcessEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    14. UnityEngine.UIElements.EventDispatcher.Dispatch (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel, UnityEngine.UIElements.DispatchMode dispatchMode) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    15. UnityEngine.UIElements.BaseVisualElementPanel.SendEvent (UnityEngine.UIElements.EventBase e, UnityEngine.UIElements.DispatchMode dispatchMode) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    16. UnityEngine.UIElements.UIElementsUtility.DoDispatch (UnityEngine.UIElements.BaseVisualElementPanel panel) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    17. UnityEngine.UIElements.UIElementsUtility.UnityEngine.UIElements.IUIElementsUtility.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr, System.Boolean& eventHandled) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    18. UnityEngine.UIElements.UIEventRegistration.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    19. UnityEngine.UIElements.UIEventRegistration+<>c.<.cctor>b__1_2 (System.Int32 i, System.IntPtr ptr) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    20. UnityEngine.GUIUtility.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr, System.Boolean& result) (at <a58ba13cea6f47f98e8c8c75d33f99e3>:0)
    21.  
    Exception 2:

    Code (CSharp):
    1. ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
    2. Parameter name: index
    3. System.ThrowHelper.ThrowArgumentOutOfRangeException (System.ExceptionArgument argument, System.ExceptionResource resource) (at <695d1cc93cca45069c528c15c9fdd749>:0)
    4. System.ThrowHelper.ThrowArgumentOutOfRangeException () (at <695d1cc93cca45069c528c15c9fdd749>:0)
    5. System.Collections.Generic.List`1[T].get_Item (System.Int32 index) (at <695d1cc93cca45069c528c15c9fdd749>:0)
    6. System.Collections.Generic.List`1[T].System.Collections.IList.get_Item (System.Int32 index) (at <695d1cc93cca45069c528c15c9fdd749>:0)
    7. UnityEngine.UIElements.ListViewDragger.MakeDragAndDropArgs (UnityEngine.UIElements.ListViewDragger+DragPosition dragPosition) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    8. UnityEngine.UIElements.ListViewDragger.GetVisualMode (UnityEngine.Vector3 pointerPosition, UnityEngine.UIElements.ListViewDragger+DragPosition& dragPosition) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    9. UnityEngine.UIElements.ListViewDragger.UpdateDrag (UnityEngine.Vector3 pointerPosition) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    10. UnityEngine.UIElements.DragEventsProcessor.OnDragUpdate (UnityEngine.UIElements.DragUpdatedEvent evt) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    11. UnityEngine.UIElements.EventCallbackFunctor`1[TEventType].Invoke (UnityEngine.UIElements.EventBase evt) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    12. UnityEngine.UIElements.EventCallbackRegistry.InvokeCallbacks (UnityEngine.UIElements.EventBase evt) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    13. UnityEngine.UIElements.CallbackEventHandler.HandleEvent (UnityEngine.UIElements.EventBase evt) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    14. UnityEngine.UIElements.EventDispatchUtilities.PropagateEvent (UnityEngine.UIElements.EventBase evt) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    15. UnityEngine.UIElements.MouseEventDispatchingStrategy.SendEventToRegularTarget (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.BaseVisualElementPanel panel) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    16. UnityEngine.UIElements.MouseEventDispatchingStrategy.SendEventToTarget (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.BaseVisualElementPanel panel) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    17. UnityEngine.UIElements.MouseEventDispatchingStrategy.DispatchEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel iPanel) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    18. UnityEngine.UIElements.EventDispatcher.ApplyDispatchingStrategies (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel, System.Boolean imguiEventIsInitiallyUsed) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    19. UnityEngine.UIElements.EventDispatcher.ProcessEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    20. UnityEngine.UIElements.EventDispatcher.Dispatch (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel, UnityEngine.UIElements.DispatchMode dispatchMode) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    21. UnityEngine.UIElements.BaseVisualElementPanel.SendEvent (UnityEngine.UIElements.EventBase e, UnityEngine.UIElements.DispatchMode dispatchMode) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    22. UnityEngine.UIElements.UIElementsUtility.DoDispatch (UnityEngine.UIElements.BaseVisualElementPanel panel) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    23. UnityEngine.UIElements.UIElementsUtility.UnityEngine.UIElements.IUIElementsUtility.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr, System.Boolean& eventHandled) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    24. UnityEngine.UIElements.UIEventRegistration.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    25. UnityEngine.UIElements.UIEventRegistration+<>c.<.cctor>b__1_2 (System.Int32 i, System.IntPtr ptr) (at <d98a0f9d3a9a450c9f1ea4983cb665e9>:0)
    26. UnityEngine.GUIUtility.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr, System.Boolean& result) (at <a58ba13cea6f47f98e8c8c75d33f99e3>:0)
    27.  
    Here's a GIF:

    2021-05-31_07-03-49.gif

    Note that I'm not attempting anything funny, using the strict minimum to get it to work.

    Last thing that'd be nice, that reordering be undoable like everything else is in Unity.
     
    Last edited: May 31, 2021