I wonder whether it is possible to specify where VisualElements are nested in a UXML template.
For example, consider a template for a titled group of elements. It has a title and an inner container:
<ui:UXML ...usual-uxml-attributes>
<ui:Label text="Group Title" name="groupTitle" />
<ui:VisualElement name="groupContainer">
<!-- I want child elements to be added here -->
</ui:VisualElement>
</ui:UXML>
Now, is there a way to specify in UXML that children elements should be added inside the “groupContainer” element?
Looking at the documentation (write uxml templates and reuse uxml files) I think it is not possible.
If this cannt be achieved with UXML alone then maybe using C#?
How can one define where child elements are added?
Yes, you can, the documentation you linked to even shows this in the example with the Box element.
For example:
<ui:UXML ...usual-uxml-attributes>
<ui:Label text="Group Title" name="groupTitle" />
<ui:VisualElement name="groupContainer">
<ui:VisualElement name="child"/>
<ui:Label text="Child Label" />
</ui:VisualElement>
</ui:UXML>
Sorry I was unclear.
I mean, if I reference above UXML as template from other UXML files, how can I specify where stuff gets added inside the referenced template?
I found this thread , which mentions overwriting contentContainer for this purpose.
Maybe this property could be added to the ui:UXML element, to specify it directly in UXML?
So it works in C# by overwriting contentContainer:
using System.Linq;
using UnityEngine;
using UnityEngine.UIElements;
public class MyGroup : VisualElement
{
public override VisualElement contentContainer => this.Q<VisualElement>("groupContainer");
// UIToolkit factory classes
public new class UxmlFactory : UxmlFactory<MyGroup, UxmlTraits> {};
public new class UxmlTraits : VisualElement.UxmlTraits
{
public override void Init(VisualElement visualElement, IUxmlAttributes bag, CreationContext cc)
{
base.Init(visualElement, bag, cc);
MyGroup target = visualElement as MyGroup;
// Load UXML
string path = "MyGroupUi"; // MyGroupUi.uxml in Resources folder
VisualTreeAsset visualTreeAsset = Resources.Load<VisualTreeAsset>(path);
if (visualTreeAsset == null)
{
Debug.LogError("Could not load " + path);
return;
}
// Add elements from loaded VisualTreeAsset as children.
visualTreeAsset.CloneTree()
.Children()
.ToList()
.ForEach(child => target.hierarchy.Add(child));
}
}
}
Still, it would be nice if contentContainer could be specified in a UXML file somehow.
However, the C# custom element works for me.
It would be nice to have such an example in the documentation for contentContainer.
And mentioning contentContainer in reuse UXML files would make sense IMO.
1 Like
Still, it would be nice if contentContainer could be specified in a UXML file somehow.
I think content-container is already exposed to UXML files. But how to use it properly?
Looks like others had the same question before and turned to using C# to overwrite contentContainer in the end.
Is there an example how to use content-container in a UXML file?
I got this working
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False"
>
<ui:Label text="Group Title" name="groupTitle" />
<ui:VisualElement name="groupContainer" content-container="groupContainer">
<!-- I want child elements to be added here -->
</ui:VisualElement>
<ui:VisualElement/>
</ui:UXML>
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
<Template path="Assets/MyTemplate.uxml" name="my-template"/>
<ui:Instance template="my-template">
<ui:Label text="Test"/>
</ui:Instance>
<ui:Instance template="my-template">
<ui:Label text="Test"/>
</ui:Instance>
</ui:UXML>
The placement of content-container seems a little strange but it does work. Ill need to confer with the team to see if this is the correct approach or if I found a bug 
Edit: This is the correct approach. The argument you provide to content-container actually doesnt matter, it can be anything. All that matters is the presence of the content-container attribute in the template and there should only be one content-container attribute used in the file.
1 Like
Support for valueless attributes was expected and would be nice:
This doesn’t work and probably should.
<VisualElement content-container />
Instead, I have to do this, which is obtuse:
<VisualElement name="contentContainer" content-container="contentContainer" />
Feels like too many speed bumps regarding productivity with UI Toolkit.
I suggest to use content-container=“true” if it is a flag.
But beware that content-container=“false” would probably work as well, which would be confusing.
Skipping the attribute value would be syntactic sugar that breaks the XML syntax. I can understand that this is not desired because it makes parsing harder and existing XML tools possibly incompatible.
In my opinion, a boolean flag that only accepts “true” and “false” would be sufficient. But as a proper boolean flag, it should ignore the precense of the attribute completely if its value is “false”.
Anyway, thanks for explaining the current behaviour.
1 Like
I believe valueless attributes are invalid XML, XML Attributes Must be Quoted.
What you can do it use an empty argument instead
<VisualElement name="contentContainer" content-container="" />
1 Like