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

Dynamic list of editable instances

Discussion in 'UI Toolkit' started by alevillalba, Dec 1, 2019.

  1. alevillalba

    alevillalba

    Joined:
    Jun 29, 2017
    Posts:
    7
    Hi everybody, it is my intention to create an EditorWindow which contains a list of elements. Each element corresponds to an instance of a class (with several fields) in a List<xxx> stored the EditorWindow. I want to be able to modify each field of any element of the list. The list is not static, it can grow.

    I know how to:
    • Create a ListView, reusing an UXML asset to create its items with makeItem. This is a read-only solution, I need to edit the fields of the items.
    • Create Template/Instance elements. This is a static solution, I need items to be added afterwards.
    • Add new VisualElements as children. This requires a lot of code that I would love to avoid.
    None of such things achieves what I want. So I have several questions:
    1. Is there a way to bind the items of the list so I can modify them directly without having to write additional code?
    2. Is there a way to bind to the element of a list by its index, in UXML?
    3. Is there a way to add new Instance objects by code, that are drawn as the defined Template describes?
    4. Is it planned to provide a way to use a Template for ListView items?
    I also tried to use PropertyDrawers with PropertyFields and so but I could not make it work and could not find one single example of how to use PropertyDrawers with UIElements in an EditorWindow :(
     
  2. alevillalba

    alevillalba

    Joined:
    Jun 29, 2017
    Posts:
    7
    I assume it's not possible for now.
     
  3. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,203
    ListView and its items are now Bindable (as of 2019.3) to a List<T> or T[] array serializable field. But this assumes your data is stored in a Unity Object that can be wrapped in a SerializedObject (that is, this works:
    new SerializableObject(yourObject)
    ). If you just have a simple C# struct with an array, you will have to write the code to bind the data to the UI yourself.

    Sort of. All of this assumes you're using SerializedObjects (like a GameObject or ScriptableObject). If so, you can use the `binding-path` attribute in UXML to address a specific item in an array by index. For example, if you had a field like this:
    Code (CSharp):
    1. public class MyLight : MonoBehaviour
    2. {
    3.     public List<Color> myColor = new List<Color>();
    4. }
    you could write some UXML like this to bind to element 1:
    Code (CSharp):
    1. <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
    2.     <uie:PropertyField binding-path="myColor.Array.data[1]" />
    3. </ui:UXML>
    4.  
    Here's a related post on this:
    https://forum.unity.com/threads/uielements-listview-with-serializedproperty-of-an-array.719570/

    If you mean the <Instance> tag, then the equivalent C# call is just:
    Code (CSharp):
    1. var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("path/to/your.uxml");
    2. var instance = template.CloneTree();
    This should already work. You need to provide a custom
    PropertyDrawer
    for your list item type, and you use the bindings system to bind your ListView to an array in an Object.

    You can also, in your
    listView.makeItem
    callback create a
    PropertyField
    element and in your
    listView.bindItem
    callback set its
    bindingPath
    to the correct array item/index in your array.

    Have you looked at:
    https://docs.unity3d.com/ScriptReference/PropertyDrawer.html
     
  4. alevillalba

    alevillalba

    Joined:
    Jun 29, 2017
    Posts:
    7
    Thank you for answering uDamian. It would be amazing to be able to do something like this:

    Code (CSharp):
    1.  
    2. <engine:VisualElement>
    3.     <engine:ListView name="list" item-height="20" class="myList" binding-path="m_items" item-template="../../ItemTemplate.uxml"/>
    4. </engine:VisualElement>
    5.  
    So we can forget about property drawers, appending visual trees, by-code configuration, etc.
     
    tonytopper likes this.
  5. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,203
    It's come up before. We need a new binding system anyway for runtime so it's a capability that might come then (for both binding systems).
     
    dsfgddsfgdsgd likes this.