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. Dismiss Notice

Question How do you create a bindable Chip/Tag group element?

Discussion in 'UI Toolkit' started by MechaWolf99, Jun 26, 2023.

  1. MechaWolf99

    MechaWolf99

    Joined:
    Aug 22, 2017
    Posts:
    290
    Hi, so I am working on a element that displays a string array as a group of chips/tags/labels.

    The question though, is how do you support binding? ListView does it by using having special built in support. Is there a way to do it without? Thanks!
     
  2. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    I imagine this is for an editor-only element, right?

    To do it without accessing the binding system, which would require reflection, your chips element needs access to the array's SerializedProperty. This means it can't just work when created from UXML, it needs some initialization from code to receive the SerializedProperty.

    You'd add a bindable chip element for each string. Then, you can bind a hidden element to the array size, or use TrackPropertyValue to know when the array size changes. When the size changes, you add/remove the necessary chip elements for each string, and rebind the whole element so any added chips are updated. You need access to the SerializedProperty, or at least the SerializedObject to be able to do this rebinding. You also need access to the property to be able to delete a chip with DeleteArrayElementAtIndex, or to reorder them with MoveArrayElement.

    I have a custom list element that deals with these kinds of problems. The code could probably use a clean up, but it may still help you as an example: ArrayPropertyField.
     
  3. MechaWolf99

    MechaWolf99

    Joined:
    Aug 22, 2017
    Posts:
    290
    Yeah right now it is editor only, but would really prefer if it didn't have to be.

    I am fine with reflection.I was taking a look at the internals some more, and you can do it by inheriting from IBinding, and adding it to the VisualTreeUpdater when the bind event happens in the BaseEvent method.
    It is a bit verbose, but that is fine. The real trick thing is I would like to not have it need to be added from within the element. So I have been looking for a way to have a static method or something listen to a global bind event and add it there or something. I will have to do some more looking.

    Your method seems like a good alternative though. Thanks for the info!
     
    oscarAbraham likes this.
  4. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    I think you could still have it work as a runtime control with my suggested approach. You'd just have to make an abstract base class with abstract methods for child classes to implement stuff like deleting/updating, etc. Or you could use something like an adapter pattern, where your main chips element receives an object that handles the relevant functionality. I think it doesn't make the code much more complex, and it's even a bit cleaner; you'd still need to pass the
    SerializedProperty
    through code, though.

    I think you could do the binding support without the
    VisualTreeUpdater
    , or a custom
    IBinding
    . I think you could do it with just the
    SerializedPropertyBindEvent
    . That event contains the
    SerializedProperty
    that your element should be bound to. That way it can work with just UXML, no custom code. You still need to implement
    IBindable
    , so the system can access its
    bindingPath
    to know which
    SerializedProperty
    you're interested in, but you can ignore the
    IBinding
    . You also need to stop propagation of that event to let Unity know that you are handling it.

    I'd suggest looking at the code for PropertyField for an example of how to use this approach.
     
  5. Wilhelm_LAS

    Wilhelm_LAS

    Joined:
    Aug 18, 2020
    Posts:
    35
    Unfortunately, SerializedPropertyBindEvent class is internal :(
     
  6. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    Yeah... :(. I think you can use reflection to access that event with some confidence if you really want the UXML support. It's a backbone of Unity's binding system, so I wouldn't expect them to remove it, at least not without adding a similar mechanism.

    Or you could pass the array property through code to your elements; it's what I do. It's not as nice as setting things up purely in UXML, but it's not too bad.