Unity中UxmlAttributeDescription无法设置值(值被重置)
问题原因及修复方案
1. 构造函数输出null的时序问题
TestElement的构造函数执行时机早于UxmlTraits.Init方法,所以构造函数里访问_status时,Init还未完成赋值,自然输出null,这是正常的执行顺序,并非bug。
2. UI Builder属性重置为空的核心问题
UI Builder无法持久化输入的属性值,根源在于:
- 私有字段
_status无法被UI Builder的序列化系统识别和跟踪; - 缺少属性变更的通知机制,导致UI Builder无法感知值的修改并保存到UXML中。
修复后的代码
using System.Collections.Generic; using UnityEngine; using UnityEngine.UIElements; public class TestElement : VisualElement, INotifyValueChanged<string> { public new class UxmlFactory : UxmlFactory<TestElement, UxmlTraits> { } public new class UxmlTraits : VisualElement.UxmlTraits { private readonly UxmlStringAttributeDescription m_status = new UxmlStringAttributeDescription { name = "status", defaultValue = "TestElementString" }; public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription { get { yield break; } } public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) { base.Init(ve, bag, cc); var testElement = ve as TestElement; string initialValue = m_status.GetValueFromBag(bag, cc); testElement.SetValueWithoutNotify(initialValue); Debug.Log($"Init后status值: {testElement.status}"); } } private string _status; // 提供公共属性,让UI Builder可以访问和修改 public string status { get => _status; set { if (_status == value) return; using (ChangeEvent<string> evt = ChangeEvent<string>.GetPooled(_status, value)) { evt.target = this; _status = value; SendEvent(evt); } } } public TestElement() { // 构造函数里拿不到初始化值,建议在附加到面板时打印 RegisterCallback<AttachToPanelEvent>(OnAttachToPanel); } private void OnAttachToPanel(AttachToPanelEvent evt) { Debug.Log("附加到面板时status值: " + _status); } // 实现INotifyValueChanged接口的方法 public void SetValueWithoutNotify(string newValue) { _status = newValue; } }
关键修改点
- 实现
INotifyValueChanged<string>接口,让UI Builder能感知属性变化并持久化值; - 将私有字段
_status封装为公共属性status,并在setter中发送变更事件; - 用
SetValueWithoutNotify初始化值,避免重复触发事件; - 把Debug.Log移到
AttachToPanelEvent回调或Init方法中,确保能拿到初始化后的正确值。
额外说明
如果是int类型属性,只需把string替换为int,对应使用UxmlIntAttributeDescription,实现INotifyValueChanged<int>接口即可,原理完全一致。
内容的提问来源于stack exchange,提问作者Daweed
相关产品推荐
相关产品推荐

