How do I clone a VisualElement?
Like, newElement = oldElement.Clone();
or newElement = new VisualElement(oldElement);
How do I clone a VisualElement?
Like, newElement = oldElement.Clone();
or newElement = new VisualElement(oldElement);
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.
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?
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ā¦
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.
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.
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ā¦
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ā¦
This is totally possible with UIElements, you can modify the tree returned by CloneTree as much as you want.
Thatās good to know ā I was assuming it would change the original.
This makes me feel a bit better about it.
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.
public class MyCustomElement : VisualElement
{
public MyCustomElement() : base() {
//TODO : Create layout
this.AddManipulator(new MyCustomElementEvent());
}
class MyCustomElementEvent : Manipulator
{
//TODO : Register, Unregister event and write event's logic.
}
//Sure if you want to clone data from some source...
public void CopyFrom(MyCustomElement source) {
//TODO : copy value, layout data from source...
}
}
ā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.
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.
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ā¦
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?
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.
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.
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:
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.
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 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.
Hi there.
Instead of cloning, Iām happy to build from an UXML, but Iām not keen on having hand coded paths kicking around, or lots of hand defined references - Iād rather find it within an existing scene. It seems to me that an ideal bridge would be to:
Is this possible?
So if I understand correctly, you would like to centralize all of your asset references in one place ? Basically only have a reference to one asset which internally serves as the library for all object types to create ?
If thatās so, I would recommend looking into creating a custom Scriptable Object which accomplishes the same job:
[CreateAssetMenu(menuName = "My Assets/TVisualTreeAsset References")]
public class VisualTreeAssetReferences : ScriptableObject
{
public VisualTreeAsset ref1;
public VisualTreeAsset ref2;
}
Then create an instance of that and manage an āhardcodedā path to it. If youāre working with game UI you can just pass a reference to it.
Then in the Inspector you can just drag and drop references to your different UXML files, use VisualTreeAsset.CloneTree() as described above.