Version: 2023.1
Create a custom control
Customize UXML tag names and attributes

Expose custom control to UXML and UI Builder

To use custom controls with UXML and UI Builder, you must expose them.

Define a factory

To define new elements, derive a new class from VisualElement or one of its subclasses, and then implement the appropriate functionality within this new class.

Your new class must implement a default constructor. For example:

class StatusBar : VisualElement
{
    public StatusBar()
    {
        m_Status = String.Empty;
    }

    string m_Status;
    public string status { get; set; }
}

In order for UI Toolkit to instantiate a new class when it reads a UXML file, you must define a factory for your class. Unless your factory needs to do something special, you can derive the factory from UxmlFactory<T>. It’s recommended that you put the factory class within your component class.

For example, the following code snippet define a factory named UxmlFactory for the StatusBar class:

class StatusBar : VisualElement
{
    public new class UxmlFactory : UxmlFactory<StatusBar> {}

    // ...
}

定义该工厂后,就可以在 UXML 文件中使用 <StatusBar> 元素。

Define attributes on elements

可为新类定义 UXML 特征,并将其工厂设置为使用这些特征。

For example, the following code snippet defines a UXML traits class to initialize the status property as a property of the StatusBar class. The status property initializes from UXML data.

class StatusBar : VisualElement
{
    public new class UxmlFactory : UxmlFactory<StatusBar, UxmlTraits> {}

    public new class UxmlTraits : VisualElement.UxmlTraits
    {
        UxmlStringAttributeDescription m_Status = new UxmlStringAttributeDescription { name = "status" };

        public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription
        {
            get { yield break; }
        }

        public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
        {
            base.Init(ve, bag, cc);
            ((StatusBar)ve).status = m_Status.GetValueFromBag(bag, cc);
        }
    }

    // ...
}

UxmlTraits 有两个作用:

  • 由工厂用于初始化新建的对象。
  • 由架构生成过程对其进行分析以获取有关元素的信息。该信息将转换为 XML 架构指令。

以上代码示例执行以下操作:

  • m_Status 的声明定义一个名为 status 的 XML 属性。
  • uxmlChildElementsDescription 返回空的 IEnumerable(表明 StatusBar 元素没有子项)。
  • Init() 成员从 XML 解析器读取属性包中的 status 属性值,并将 StatusBar.status 属性设置为此值。
  • The UxmlTraits class is placed inside the StatusBar class. This allows the Init() method to access the private members of StatusBar.
  • 新的 UxmlTraits 类继承自基类 UxmlTraits,因此其共享基类的属性。
  • Init() 调用 base.Init() 来初始化基类属性。

The code example above declares a string attribute with the UxmlStringAttributeDescription class. UI Toolkit supports the following types of attributes and each links a C# type to a UMXL type:

属性 属性值
UxmlStringAttributeDescription 字符串
UxmlFloatAttributeDescription C# float 类型范围内的单精度浮点值。
UxmlDoubleAttributeDescription C# double 类型范围内的双精度浮点值。
UxmlIntAttributeDescription C# int 类型范围内的整数值。
UxmlLongAttributeDescription C# long 类型范围内的长整数值。
UxmlBoolAttributeDescription truefalse
UxmlColorAttributeDescription A string that represents a color defined in USS format.
UxmlEnumAttributeDescription<T> A string that represents one of the values for the Enum type T.
UxmlTypeAttributeDescription<T> A string that represents the assembly-qualified name of the type.
UxmlAssetAttributeDescription<T> A string that represents an asset.

In the code example above, the uxmlChildElementsDescription returns an empty IEnumerable which indicates that the StatusBar element doesn’t accept child element descriptions to the XML schema.

To have an element accept children of any type, you must override the uxmlChildElementsDescription property. For example, for the StatusBar element to accept children of any type, you must specify the uxmlChildElementsDescription property as follows:

public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription
{
    get
    {
        yield return new UxmlChildElementDescription(typeof(VisualElement));
    }
}

Define a namespace prefix

Once you have defined a new element in C#, you can use the element in your UXML files. To categorize elements, create your class in a namespace. When you define a new namespace, you can define a prefix for the namespace. You must define namespace prefixes as attributes of the root <UXML> element and replace the full namespace name when scoping elements.

To define a namespace prefix, add a UxmlNamespacePrefix attribute to your assembly for each namespace prefix. For example:

[assembly: UxmlNamespacePrefix("My.First.Namespace", "first")]
[assembly: UxmlNamespacePrefix("My.Second.Namespace", "second")]

此操作可以在程序集的任何 C# 文件的根级别(在任何命名空间之外)完成。

架构生成系统会执行以下操作:

  • 检查是否有这些属性并使用它们来生成架构。
  • Adds the namespace prefix definition as an attribute of the <UXML> element in newly created UXML files.
  • 将命名空间的架构文件位置包含在其 xsi:schemaLocation 属性中。

To ensure that your text editor recognizes the new element, select Assets > Update UXML Schema to update the schema definition.

To create a new UXML document with the prefix, select Assets > Create > UI Toolkit > UI Document.

其他资源

Create a custom control
Customize UXML tag names and attributes