Hi folks!
Context:
Unity 2019.4.9f1
UI Builder: 1.0.0-preview7
I am creating a fancy tool using uielements and to keep my project organized I decided to create some custom components. I ready the documentation and a few examples and I had a good start.
Basically, I created 6 components. One of them is very “basic” and is used but others… and these are used by another. So, I have custom controls that consume other custom controls. So far, so good. Everything working fine.
BOOM
Out of the blue I started to have one of my components getting changed (by the builder) for a label with the text: “Unknow type: UIRichLabel”. This is (just a coincidence) my most basic custom control. It is a label with an icon. This is the UXML of it:
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
<ui:VisualElement name="UIRichLabel" style="flex-direction: row; align-items: center;">
<Style src="FtueEditorWindow3.uss" />
<ui:VisualElement name="icon" class="hide" style="margin-left: 5px; margin-right: 5px; justify-content: center;" />
<ui:Label text="LABEL" name="label" style="font-size: 12px;" />
</ui:VisualElement>
</ui:UXML>
And this is its related c# code
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
public class UIRichLabel : VisualElement
{
private const string TEMPLATE_PATH = "Assets/Editor/FTUE/UIRichLabelTemplate.uxml";
private const string ERROR_ICON_STYLE = "error_icon";
private const string WARNING_ICON_STYLE = "warning_icon";
private const string INFO_ICON_STYLE = "info_icon";
private const string NONE_ICON_STYLE = "hide";
public enum IconStyle
{
None,
Error,
Warning,
Info
}
public static readonly Dictionary<IconStyle, string> IconStyles = new Dictionary<IconStyle, string>()
{
{IconStyle.None, NONE_ICON_STYLE},
{IconStyle.Error, ERROR_ICON_STYLE},
{IconStyle.Warning, WARNING_ICON_STYLE},
{IconStyle.Info, INFO_ICON_STYLE},
};
private const string ICON_SELECTOR = "icon";
private const string LABEL_SELECTOR = "label";
private VisualElement m_icon = default;
private Label m_label = default;
private IconStyle m_iconStyle;
private Color m_color = default;
public string Label
{
get { return m_label.text; }
set { m_label.text = value; }
}
public int TextSize
{
get { return (int)m_label.style.fontSize.value.value; }
set
{
m_label.style.fontSize = new StyleLength(value);
m_icon.style.height = new StyleLength(value);
m_icon.style.width = new StyleLength(value);
}
}
public Color TextColor
{
get { return m_color; }
set
{
m_color = value;
m_label.style.color = m_color;
}
}
public IconStyle Icon
{
get { return m_iconStyle; }
set
{
m_iconStyle = value;
SetStyle(m_iconStyle);
}
}
public UIRichLabel()
{
VisualTreeAsset template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(TEMPLATE_PATH);
template.CloneTree(this);
LoadInternalReferences();
}
public void LoadInternalReferences()
{
m_icon = this.Q<VisualElement>(ICON_SELECTOR);
m_label = this.Q<Label>(LABEL_SELECTOR);
}
public void SetLabel(string title, IconStyle style)
{
SetLabel(title);
SetStyle(style);
}
public void SetLabel(string label)
{
m_label.text = label;
}
public void SetStyle(IconStyle style)
{
m_icon.ClearClassList();
m_icon.AddToClassList(IconStyles[style]);
}
public void SetClickCallback(Action callback)
{
m_label.AddManipulator(new Clickable(callback));
}
#region UXML stuff
public new class UxmlFactory : UxmlFactory<UIRichLabel, UxmlTraits> { }
public new class UxmlTraits : VisualElement.UxmlTraits
{
UxmlEnumAttributeDescription<IconStyle> m_icon = new UxmlEnumAttributeDescription<IconStyle> { name = "icon-style", defaultValue = IconStyle.None };
UxmlStringAttributeDescription m_label = new UxmlStringAttributeDescription { name = "label", defaultValue = "Label" };
UxmlIntAttributeDescription m_textSize = new UxmlIntAttributeDescription { name = "text-size", defaultValue = 12 };
UxmlColorAttributeDescription m_textColor = new UxmlColorAttributeDescription { name = "text-color", defaultValue = Color.black };
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
{
base.Init(ve, bag, cc);
UIRichLabel uIRichLabel = ve as UIRichLabel;
uIRichLabel.Label = m_label.GetValueFromBag(bag, cc);
uIRichLabel.Icon = m_icon.GetValueFromBag(bag, cc);
uIRichLabel.TextSize = m_textSize.GetValueFromBag(bag, cc);
uIRichLabel.TextColor = m_textColor.GetValueFromBag(bag, cc);
}
}
#endregion
}
When I pass the mouse over another component (in the builder) that uses this richlabel, I got this in the console:
Element ''UIRichLabel'' has no registered factory method.
UnityEngine.UIElements.VisualTreeAsset:CloneTree()
Unity.UI.Builder.<>c__DisplayClass8_0:<ImportUxmlFromProject>b__0() (at Library/PackageCache/com.unity.ui.builder@1.0.0-preview.7/Editor/Builder/Library/BuilderLibraryProjectScanner.cs:248)
Unity.UI.Builder.BuilderLibraryView:OnItemMouseEnter(MouseEnterEvent) (at Library/PackageCache/com.unity.ui.builder@1.0.0-preview.7/Editor/Builder/Library/BuilderLibraryView.cs:93)
UnityEngine.GUIUtility:processEvent(Int32, IntPtr)
I read several posts about the possible causes, I saw it used to be related to
moment when the the uxmlfactory got registred, I saw a few hacks to work it around… but all old stuff, version 0.0.4 or something like that and supposely already fixed.
After 3 days trying to fix that…
BOOOOOM
Another components start to present the same symptom!! Seems like a cancer spreading out across my components!!
Please, I need to advices here… anyone with a word to comfort me is also welcome.
Joao