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

Resolved Fastest Way To Sort Elements In A Container Very Often

Discussion in 'UI Toolkit' started by Monogenesis, Feb 6, 2022.

  1. Monogenesis

    Monogenesis

    Joined:
    Dec 30, 2019
    Posts:
    56
    Hello,

    I'm currently working on a UI for a racing game, where the leaderboard needs to be updated frequently.

    So the first thing I do is, updating the values on the elements (Labels) in the leaderboard container and then sort the children by a key value (e.g. Position) with LeaderboardContainer.Children().OrderBy.
    Now when I need to reorder the VisualElements in the container I add them again in a for loop to the container to display them in order.
    But when I add them like that, the game becomes laggy very quickly when there are 10+ entries in the leaderboard.

    Does anyone have a suggestion on how to order the child elements in a container performant?
     
  2. Monogenesis

    Monogenesis

    Joined:
    Dec 30, 2019
    Posts:
    56
    I found out that VisualElements have a sorting method. This has improved the performance a lot. But still, if there are many more entries in the ScrollView, it gets laggy.

    Speaking of ScrollView, tomorrow I will test it with a ListView implementation.
     
  3. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    229
    Hi,

    The ListView is using virtualization of items and is recommended when there are a large amount of elements to display.
     
  4. Monogenesis

    Monogenesis

    Joined:
    Dec 30, 2019
    Posts:
    56
    How can I add new elements at runtime to a ListView? When i update the sourceItem nothing happens and adding them regulary with .Add does not work.
     
  5. Monogenesis

    Monogenesis

    Joined:
    Dec 30, 2019
    Posts:
    56
    I found out that you can set the makeItem callback again when you add a new entry and then it shows up but I dont know if there is better way.
     
  6. Monogenesis

    Monogenesis

    Joined:
    Dec 30, 2019
    Posts:
    56
    Ok, i got the ListView working but i see now that the .sort method is unstable. What would be the best approach to sort the elements in a ListView in a stable manner?
     
  7. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    229
    When the item source changes you need to call Refresh to update the ListView.
     
  8. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    229
    I would sort the item source and then Refresh the ListView.
     
  9. Monogenesis

    Monogenesis

    Joined:
    Dec 30, 2019
    Posts:
    56
    What would be the easiest way to sort the item source stable?
     
  10. Monogenesis

    Monogenesis

    Joined:
    Dec 30, 2019
    Posts:
    56
    The ListView does not seem to become sorted just by chaninging the sort order from the item source. When I debug the lists the item source is sorted correctly but not the ListView,
     
  11. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    229
    Just wrote a simple example that you can refer to.

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using UnityEditor;
    4. using UnityEngine.UIElements;
    5.  
    6. public class ListViewSort : EditorWindow
    7. {
    8.     [MenuItem("UIElementsExamples/ListViewSort")]
    9.     public static void OpenDemoManual()
    10.     {
    11.         GetWindow<ListViewSort>().Show();
    12.     }
    13.  
    14.     public class Item : IComparable
    15.     {
    16.         public readonly int index;
    17.  
    18.         public Item(int index)
    19.         {
    20.             this.index = index;
    21.         }
    22.  
    23.         public int CompareTo(object obj)
    24.         {
    25.             if (obj == null) return 1;
    26.  
    27.             Item otherItem = obj as Item;
    28.             if (otherItem != null)
    29.                 return index.CompareTo(otherItem.index);
    30.  
    31.             throw new ArgumentException("Object is not an Item");
    32.         }
    33.     }
    34.  
    35.     private List<Item> m_Items;
    36.     private ListView m_ListView;
    37.  
    38.     private void CreateGUI()
    39.     {
    40.         const int itemCount = 1000;
    41.  
    42.         var root = rootVisualElement;
    43.  
    44.         m_Items = new List<Item>(itemCount);
    45.         for (int i = itemCount; i > 0; i--)
    46.             m_Items.Add(new Item(i));
    47.  
    48.         Func<VisualElement> makeItem = () => new Label();
    49.  
    50.         Action<VisualElement, int> bindItem = (e, i) => (e as Label).text = m_Items[i].index.ToString();
    51.  
    52.         m_ListView = new ListView(m_Items, 30, makeItem, bindItem);
    53.         m_ListView.showAlternatingRowBackgrounds = AlternatingRowBackground.ContentOnly;
    54.  
    55.         var sortButton = new Button(SortItems);
    56.         sortButton.text = "Sort";
    57.  
    58.         root.Add(sortButton);
    59.         root.Add(m_ListView);
    60.     }
    61.  
    62.     void SortItems()
    63.     {
    64.         m_Items.Sort();
    65.         m_ListView.Refresh();
    66.     }
    67. }
     
    Monogenesis and SimonDufour like this.
  12. Monogenesis

    Monogenesis

    Joined:
    Dec 30, 2019
    Posts:
    56
    Thank you for this example. I had to sort my list with OrderBy() because Sort() did not work for me.

    But it is working now!! Thank you!
     
    jonathanma_unity likes this.
  13. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,256
    OrderBy() will create a new collection, so if your not updating ListView to point to the newly created collection it will not update.
     
    Monogenesis and jonathanma_unity like this.
  14. Monogenesis

    Monogenesis

    Joined:
    Dec 30, 2019
    Posts:
    56
    Yeah, you are totally right. I forgot to mention that. Thanks!
     
  15. Alobal17

    Alobal17

    Joined:
    Aug 2, 2019
    Posts:
    9
    Is there any way to sort ListView without sort data source? Well,you know....some time we need UI and data separation。
     
  16. stevphie123

    stevphie123

    Joined:
    Mar 24, 2021
    Posts:
    74
    Sorting the itemSource back and fourth sounds like reasonable way to do it. Also not quite sure what you mean with data separation.

    If your List is value type then make a copy of it `List<T> lis = new List<T>(myList);` sort it out then use it as your itemSource
     
  17. Alobal17

    Alobal17

    Joined:
    Aug 2, 2019
    Posts:
    9
    Yeah thanks~, copy itemSource is a solution that I have tried, it is a good solution in most cases. However, it is not suitable in some cases where you need to retain the ability to modify the data source. It seems like the View concept in Relational database.

    e.g., I have built a ListView in an ItemCreator Editor, which is used to modify the data in ItemDataSource. All the data are sorted by x.ID in the ItemDataSource. However, I want to sort the ListView by x.Name. If I copy the itemSource, the Editor will not be able to modify origin data.

    For this case , I have found a function called ListView.Sort(CustomComparisionFunction), which seems like what I need. However, it doesn't work anymore, even the CustomComparisionFunction is not called. https://forum.unity.com/threads/lis...ot-enter-in-the-comparision-function.1428546/