UiToolkit can't Q<> my custom VisualElement

Hey there,

i am once again confused and have a (basic) UiToolkit question.

I want to create a Editor only panel. Therefore I created a class TypeSettingsPanel and inheritted from VisualElement and I also created a uxml for it.
I try to Q<> my TypeSettingsPanel class from my EditorWindow to pass data to it and set it up correctly. But for some reason I can’t … all my aproaches return null. Any idea why that could be ? :thinking: I was under the assumption I can Q all classes which inherit from VisualElement. If not, how can I get it?

uxml

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="True">
    <ui:VisualElement name="typeSettingsPanel" style="flex-grow: 1; flex-shrink: 0; overflow: hidden;">
// more unrelated stuff here I guess

    </ui:VisualElement>
</ui:UXML>

My Custom Visual Element

using Packages.GSK_CoreUtils.Editor.Ui;
using UnityEngine.UIElements;

public class TypeSettingsPanel : VisualElement
{
    [UnityEngine.Scripting.Preserve]
    public new class UxmlFactory : UxmlFactory<TypeSettingsPanel> { }

    public TypeSettingsPanel()
    {
        
    }
}

My EditorWindowClass:

public class MyEditorWindow: EditorWindow
{
    [SerializeField] private VisualTreeAsset _visualTreeAsset = default;
    [SerializeField] private VisualTreeAsset _typeSettingsPanelTemplate = default;

    private TypeSettingsPanel _typeSettingsPanel;

    [MenuItem("Window/MyEditorWindow")]
    public static void Show()
    {
        MyEditorWindow wnd = GetWindow<MyEditorWindow>();
        wnd.titleContent = new GUIContent("MyEditorWindow");
    }

    public void CreateGUI()
    {
        VisualElement root = rootVisualElement;

        VisualElement labelFromUXML = _visualTreeAsset.Instantiate();
        root.Add(labelFromUXML);

		// This works
        TemplateContainer existingTemplateContainer = rootVisualElement.Q<TemplateContainer>("TypeSettingsPanel");  

		// this returns also null
        TypeSettingsPanel typeSettingsPanel2 = existingTemplateContainer.Q<TypeSettingsPanel>(); 
        // this works
		VisualElement typeSettingsPanel3 = rootVisualElement.Q<VisualElement>("typeSettingsPanel"); 
        // this cast returns null
		TypeSettingsPanel typeSettingsPanel4 = typeSettingsPanel3 as TypeSettingsPanel; 
        
		// this returns null
        var settingsPanel = rootVisualElement.Q<TypeSettingsPanel>(); 

        var newTemplateContainer = _typeSettingsPanelTemplate.Instantiate();
        root.Add(newTemplateContainer);
		// this returns also null
        var typeSettingsPanel = newTemplateContainer.Q<TypeSettingsPanel>(); 
    }
}

I enriched the code with comments which lines return null or not for clarification. Any idea what I do wrong ? :thinking:

Thanks a lot for your help!
Cxyda

Hi CxydaIO, the reason you can’t use Q<TypeSettingsPanel>() is because you have not added a TypeSettingsPanel to your UXML file. You need to replace the ui:VisualElement with TypeSettingsPanel in your UXML file:

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="True">
    <TypeSettingsPanel name="TypeSettingsPanel" style="flex-grow: 1; flex-shrink: 0; overflow: hidden;"/>
</ui:UXML>

Hope this helps.

2 Likes

hey @martinpa_unity !

Thanks for your answer! I was already facepalming myself when I read your answer because it absolutely makes sense! BUT I tried it and it still does not work :exploding_head:

My new uxml as you suggested

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="True">
    <TypeSettingsPanel name="TypeSettingsPanel" style="flex-grow: 1; flex-shrink: 0; overflow: hidden;">
// ... more stuff here
    </TypeSettingsPanel>
</ui:UXML>

hmm, after restarting the Editor I get an actual error in the console:

Element ‘TypeSettingsPanel’ has no registered factory method.

which is weird because it has a factory method.

Ui builder now also shows me Unknown type: 'TypeSettingsPanel' in the design

is there maybe some weird namespace issue going on? I only have a single class called TypeSettingsPanel but it sits in an Editor assembly :thinking: :man_shrugging:

edit: Okay both of the mentioned errors here were resolved by adding the fully qualified name of the class to the xml. Wasn’t aware that this is necessary and doesn’t make me happy since this makes things very fragile… renaming class or namespaces would result in breaking all Uis :-1:

Thanks for help @martinpa_unity

1 Like

You can also use the xmlns property on the UXML tag to have a prefix for your namespace, like in the example: xmlns:ui="UnityEngine.UIElements".

We need to resolve to the full type name because there would be a lot of clashes otherwise.

Yes I get that, and good to know, thanks. But hardcoding class and namespace names at places where your IDEs does not help you when it comes to renaming, does not make the the development process more resilient. Anyway… one more thing to keep in mind.

Thanks for your quick help!