Search Unity

  1. Unity 2020.1 has been released.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

How to make a clone/copy of a VisualElement?

Discussion in 'UI Toolkit' started by Vapid-Linus, Aug 7, 2019.

  1. Vapid-Linus

    Vapid-Linus

    Joined:
    Aug 6, 2013
    Posts:
    64
    How do I clone a VisualElement?

    Like,
    newElement = oldElement.Clone();
    or
    newElement = new VisualElement(oldElement);
     
  2. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    101
    Hi,

    There's no way to clone a VisualElement.
    What you can do instead is to create a new VisualElement and then set the same USS classes, event handlers and so on.
     
  3. Vapid-Linus

    Vapid-Linus

    Joined:
    Aug 6, 2013
    Posts:
    64
    Thank you for the reply.

    The thing is that the visual element has several nested children as well. Manually copying everything is pretty tedious. I guess a method that manually copies everything could be created, but I feel a simple copy/clone method should be part of the standard API. I can think of several use cases for it and feel that will be a fairly common request.

    Is the planned? If not, why not?
     
  4. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    101
    To my knowledge this is the first time that a request for VisualElement cloning comes.
    I don't think this is planned, but I'll start a discussion about it.

    Meanwhile if you want to clone hierarchy of elements I'd recommend using UXML with VisualTreeAsset.CloneTree. This way you can create a tree of elements with the same set of properties.

    A clone function may sound really simple on the surface, but it actually isn't. There are many internal properties to a VisualElement and some of them are trivial to clone and others are not or must not be cloned at all. There's also the case of element inheriting from VisualElement...
     
    Vapid-Linus likes this.
  5. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,540
    From my testing, it's best to use an MVC pattern with a Clone function on the model it will automatically deliver the correct VisualElement from your view.
     
  6. Vapid-Linus

    Vapid-Linus

    Joined:
    Aug 6, 2013
    Posts:
    64
    I appreciate your reply and your explanation, thank you. That makes a lot of sense.

    I understand that visualTreeAsset.CloneTree is the only way to create/clone elements without creating them through C#. My problem is that there are a lot of different element-trees that I want to clone/copy for lists and such. I do not wish to create those manually with code as they are quite complex and I want to iterate quickly, and having to create different UXML files for every element-tree I want to clone will create a lot of UXML files which is a bit tedious. Is there a way (or is it even feasible) to use CloneTree on just a part of a tree asset? Like querying (by class or name) for a specific element within a tree asset and creating a clone of just that element?

    Thank you for your time.
     
  7. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    101
    From what I understand this statement is contradictory, if the element-trees are not created from UXML they must have been created manually from code. If that is the case it's just a matter of creating some functions that would create the desired hierarchy and reuse that code where needed.

    But to answer your question CloneTree works on a full VisualTreeAsset only.

    Finally, may I suggest that you try to approach your problem in a different way?
    There are many other options to VisualElement cloning, I don't see any compelling reasons to do so personally but I may be missing something. And if it's not enough you still have the possibility of creating your own cloning function...
     
  8. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    1,069
    This seems like a shame... Can these be nested?

    UI stuff really needs the ability to be swappable with other elements. I should be able to take a whole form within an EditorWindow and swap it out with a different form....



    I'm already very hesitant on VisualElements and this isn't helping... :(
     
  9. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    101
    This is totally possible with UIElements, you can modify the tree returned by CloneTree as much as you want.
     
  10. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    1,069
    That's good to know -- I was assuming it would change the original.

    This makes me feel a bit better about it.
     
  11. Creta_Park

    Creta_Park

    Joined:
    Mar 11, 2016
    Posts:
    57
    Might be near of topic, how about use instead override class to create layout itself?
    VisualElement
    is not sealed class, so you can override it.

    Code (CSharp):
    1. public class MyCustomElement : VisualElement
    2. {
    3.     public MyCustomElement() : base() {
    4.         //TODO : Create layout
    5.         this.AddManipulator(new MyCustomElementEvent());
    6.     }
    7.  
    8.     class MyCustomElementEvent : Manipulator
    9.     {
    10.         //TODO : Register, Unregister event and write event's logic.
    11.     }
    12.  
    13.     //Sure if you want to clone data from some source...
    14.     public void CopyFrom(MyCustomElement source) {
    15.         //TODO : copy value, layout data from source...
    16.     }
    17. }
    'UIElements base class is overridable' means lot of possibilities to customization, so able to make own scripted, functional element.
    You should try with it.

    I had with this possibilities.
    https://creta5164.tumblr.com/post/187093161546/second-week-of-20198-white-spirit-dev-status

    ME3MG8d.gif
     
    awesomedata likes this.
  12. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    887
    Although we encourage encapsulation where possible, VisualElement was made to be inherited from and overridden. This is how you make custom elements with custom behavior, like a TreeView.
     
    Creta_Park likes this.
  13. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    1,069
    Can you get someone to do this override magic for the SceneCameraController so that I can make my own SceneCameraController for the SceneView please?

    I want my orbit behavior to work differently than the standard Unity one...
     
  14. Suduckgames

    Suduckgames

    Joined:
    Nov 28, 2016
    Posts:
    191
    I will like to support the clone function on a visual element. I am new to UI Elements and I may be doing something wrong or thinking it in a wrong way, so feel free to correct/guide me.

    Coming from the android background. I am trying to do a dynamic ListView and separating the adapter .uxml files In order to reutilize them in different list views. So each time that I am using them in a list view I need to first create a clone to know the height of the layout. And then each time that a new item is required, create a copy of the adapter file from the VisualTreeAsset.

    Is that the way it is meant to work? In my head, I want to get a concrete visual element and N copies of it. Instead of copy the whole file. If I only want to populate a listview with part of the adapter I should be able to create copies of the specific part. If not, I am forced to separate each part of the adapter in each file and build them manually or lookup for the specific part each time that a new object is required.

    Is that correct? I am missing something?
     
  15. Refeas

    Refeas

    Joined:
    Nov 8, 2016
    Posts:
    108
    As a webdev I really like the way UI Toolkit is done and I see a lot of people struggle with the concept in some ways. Hope this will shed some light on the concept.
    Try to imagine the UXML assets as templates/components/views. So, let's say you want a list of players. So you create the base template containing the layout, the ListView, etc. Then you want to design each entry of the player list. So you go ahead and create some playerentry.uxml asset, design that the way you'd like the player entries to look in the list. And then, via script, you set the itemSource, makeItem and bindItem functions of the ListView. In the makeItem function, you can use the CloneTree method on the playerentry.uxml asset which will populate the list of players with your designed entries automagically. Then you can use the bindItem function to set the proper data values on the playerentry subelements.

    TL;DR: I think creating multiple UXML assets (for base templates, specific child items etc.) is the proper way to go as it will separate neccessary views and will be more organized in a long run. Didn't really think of a need for Clone function as of yet.
     
  16. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    887
    Just to shed more light, as Refeas above mentione, UXML is the "clone" feature you are looking for. The C# equivalent is the standard "C# function" (you can always create a function that creates a specific set of element in C#, so kinda like a "clone"). For something like ListView, indeed, you'd want two UXML files, one for the main UI that contains the ListView and one for the "template" of each of the items.

    As for why it's not possible to clone a C# VisualElement. This is because elements are C# Objects. They have non-trivial constructors which can often create more child elements, state that cannot be serialized like C# Properties, references to other VisualElements, and often registered callbacks made by interested parties. Also VisualElements have no unique identifiers so if one VisualElement references another, this reference is only stable at runtime while those two elements exist as Objects. It needs to be recreated when the elements are recreated.

    While it would be nice to be able to "clone" a UI element, it would prevent us from having the advantages we have now that they are actual C# objects. Hence, to get something close to a clone, we implemented the UXML approach.
     
  17. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,951
    The UI Elements Debugger clearly shows that you're able to convert the C# objects to uxml. You list all the VisualElements and all their classes, names, inline properties, etc. You can pretty trivially build uxml from that.

    At the same time, you're obviously able to generate the VisualElement objects from uxml.

    So it should not be hard to implement clone through first generating the uxml from the VisualElement, then creating new VisualElements from that uxml.


    Doing that approach would also have two huge benefits:
    - It'd really be nice to output the generated uxml, both for debugging and for editor tools that wants to build UI.
    - It'd be really nice at times to generate VisualElements from a uxml string rather than an asset. That'd allow things like implementing a newsfeed in your main menu simply by downloading the uxml/uss text from a url.

    Does the uxml asset wrapper contain some kind of accelerator/serialized version of the generated objects rather than just the text? If it just parses the uxml file from text at runtime, the only thing keeping this from already working is access modifiers on Unity internals, but it could be more complex, idk.
     
  18. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    887
    This is not an accurate conversion. It's just a bit of help to have something to start with. It may not even be valid UXML. It just reflects the VisualElement types and generates UXML <tags> with the full type name. A lot of information is lost.

    As I explained above, UXML -> VisualElements is a one-way conversion, where the end result has more information and state than can be represented in UXML. Going back from VisualElement -> UXML is not generally possible for the same reason why compiled object files cannot be converted back to source code. Yes, you "can" do an approximated conversion, with lots of exceptions and pitfalls, and you are free to do that for your own code in the same way the UI Debugger does it (if you get the UI Toolkit package, the Debugger code is there so you can see how it generates that UXML). But we won't release such a feature because the expectation will be that it works "all the time" and reliably.

    This will be possible at some point. We just didn't make the function you need public. It's a method on our UXML importer that we use after we read the contents of the .uxml file. UI Builder converts UXML to VisualElements in memory all the time. If you copy some elements in the Builder and you paste in a text editor, you'll see that what you copied was UXML. The UI Builder can generate UXML in this case because it uses the main asset UXML you have open as the source, not the live VisualElements you see in the work area. It just extracts the bit of UXML from main asset.

    Yes, the VisualTreeAsset, which is the C# object generated from importing a text-based .uxml file, is indeed optimized for runtime use. We do not parse UXML at runtime by default for performance reasons.
     
unityunity