Daweed
Daweed

Reputation: 85

Unity UxmlAttributeDescription not setting values (resetting values)

I'm using the UI Builder for my UI and I'm creating some custom controls. I've already managed to make a custom control which works perfectly fine. But the second one has some problems I can't understand.

The problem: I'm able to put my custom control into the UI Builder. From the start there is no default value in the "status" attribute, it just blank. When I manually input a value and click away, the "status" value is reset to blank. In the console I'm getting the message "null" from the constructor, meaning the value I input was not set.

Additional information: The problem first occurred when I used the class UxmlIntAttributeDescription. I had a class with an UxmlStringAttributeDescription and an UxmlIntAttributeDescription. I was able to set the string attribute, but not the int attribute. I kept simplifying my code so I can post this question and then even the string attribute broke. I really don't know where I screwed up, hopefully someone can help me with this one.

Here is my code. Its mostly copied from https://docs.unity3d.com/Manual/UIE-UXML.html.

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;

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

    public new class UxmlTraits : VisualElement.UxmlTraits {

        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 ate = ve as TestElement;

            ate._status = m_status.GetValueFromBag(bag, cc);
        }
    }

    private string _status;
    
    public TestElement() {
        Debug.Log(_status);
    }
}

Upvotes: 3

Views: 1170

Answers (3)

Lars Lundh
Lars Lundh

Reputation: 11

The real answer turns out to be that you need a getter and setter for the member variable, and it must match the name field.

UxmlStringAttributeDescription meow = new UxmlStringAttributeDescription { name = "my-example-value", defaultValue = "TestElementString" };

with a name like that you need a getter and setter excactly like this:

private string MyExampleValue { get; set; }

The source material: https://forum.unity.com/threads/uxmltraits-and-custom-attributes-resetting-in-inspector.966215/

Upvotes: 1

robinryf
robinryf

Reputation: 416

This could have changed throughout the updates. Just reporting in that I am using Unity 2022.3.10f1 and in my tests the only important thing is that the variable name of the VisualElement must match with the name property of the UxmlAttributeDescription

So this should work out fine:

enter code here

public class TestElement : VisualElement
{
    public string myCustomValue { get; set; }

    public new class UxmlFactory : UxmlFactory<TestElement,UxmlTraits> {}
    public new class UxmlTraits : VisualElement.UxmlTraits
    {
        UxmlStringAttributeDescription thisNameDoesNotMatter = 
            new UxmlStringAttributeDescription 
            { 
                name = "my-custom-value",
                defaultValue = "TestElementString"
            };
        public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
        {
            base.Init(ve, bag, cc);
            var ate = ve as TestElement;

            ate.myCustomValue = thisNameDoesNotMatter.GetValueFromBag(bag, cc);
        }
    }
}

Upvotes: 0

Andrew Łukasik
Andrew Łukasik

Reputation: 1637


  • AttributeDescription's name should end with Attr suffix
  • corresponding public {get;set;} property must exist & named the same but without that Attr suffix

Serialization system won't work with this element otherwise.

public class TestElement : VisualElement
{
    public string status { get; set; }
    public new class UxmlFactory : UxmlFactory<TestElement,UxmlTraits> {}
    public new class UxmlTraits : VisualElement.UxmlTraits
    {
        UxmlStringAttributeDescription statusAttr = new UxmlStringAttributeDescription { name = "status", defaultValue = "TestElementString" };
        public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
        {
            base.Init(ve, bag, cc);
            var ate = ve as TestElement;

            ate.status = statusAttr.GetValueFromBag(bag, cc);
        }
    }
}

Upvotes: 4

Related Questions