Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Default values of inherited fields not shown in UI Builder

Discussion in 'UI Toolkit' started by manuelgoellnitz, Jun 9, 2020.

  1. manuelgoellnitz

    manuelgoellnitz

    Joined:
    Feb 15, 2017
    Posts:
    365
    When I add a standard UIElement "Button" into the hierarchy in the UI Builder, it fills the Text-Field with the default value "Button".

    Then I wrote an Class "ButtonTranslatable" that inherits form the UIElement Button and adds a new attribute "TranslationKey".
    When I add this "ButtonTranslatable" into the hierarchy in the UI Builder the Value of the Text Field is empty.

    I just wrote it like described here
    https://docs.unity3d.com/2019.1/Documentation/Manual/UIE-UXML.html
    But instead of VisualElement I inherited form Button.
     
  2. Mrbeardy

    Mrbeardy

    Joined:
    Jun 30, 2014
    Posts:
    13
    For the standard elements, UI Builder is setting default attributes when you add them in from the Library panel:

    Code (CSharp):
    1. new BuilderLibraryTreeItem("Button", nameof(Button), typeof(Button), () => new Button { text = "Button" })
    This is why it has a default text value of "Button", the default values are being added by UI Builder, not in UI elements.

    If you want your
    ButtonTranslatable
    class to have a default value for the existing text attribute, you'll need to set it in the
    Init
    method for its
    UxmlTraits
    :

    Code (CSharp):
    1.     public class ButtonTranslatable : Button
    2.     {
    3.         public new class UxmlFactory : UxmlFactory<ButtonTranslatable, UxmlTraits> { };
    4.  
    5.         public new class UxmlTraits : Button.UxmlTraits
    6.         {
    7.             public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
    8.             {
    9.                 base.Init(ve, bag, cc);
    10.  
    11.                 ButtonTranslatable buttonTranslatable = ve as ButtonTranslatable;
    12.                 buttonTranslatable.text = "Translated Button";
    13.             }
    14.         };
    15.     }
     
    Last edited: Jun 9, 2020
  3. manuelgoellnitz

    manuelgoellnitz

    Joined:
    Feb 15, 2017
    Posts:
    365
    Unfortunatelly this would override any value of the "text"-attribute in an uxml file to "Translated Button".

    But I you are correct with you first sentence:
    When I drag a "Button" into the Hierarchy it adds "<ui:Button text="Button" />" to the uxml file.
    But when I drag a "ButtonTranslatable" into the Hierarchy it only adds "<ButtonTranslatable />".

    So is there a way to modify that behavior? Is there a way to add a custom "new BuilderLibraryTreeItem()" entry somewhere?
    Which leads to another question: Is there a way to change the icon of a custom UiElement in the UI Builder?
     
  4. Mrbeardy

    Mrbeardy

    Joined:
    Jun 30, 2014
    Posts:
    13
    Ah that's true, my bad.

    Looking through the UI Builder code some more, it seems like it's calling the
    Create
    method in the factory when it's running
    BuilderLibraryTreeItem
    for custom classes.

    I tried setting the default attributes in this method, but it was still resetting the attributes to the hard-coded value whenever UI Builder changed.

    Instead, using
    Create
    , you may be able to achieve the desired result by checking whether the attribute has any value, then setting a value on it:

    Code (CSharp):
    1. public new class UxmlFactory : UxmlFactory<ButtonTranslatable, UxmlTraits> {
    2.     public override VisualElement Create(IUxmlAttributes bag, CreationContext cc)
    3.     {
    4.         VisualElement visualElement = base.Create(bag, cc);
    5.  
    6.         Button button = visualElement as Button;
    7.  
    8.         if (button.text.Length == 0)
    9.             button.text = "Translated Button";
    10.  
    11.         return visualElement;
    12.     }
    13. };
    Unfortunately this also has its drawbacks, as it will actually set it back to the hardcoded value if the text is made blank at any point. It's not ideal, and there may be a cleaner or better way to do it, but hopefully it works for now.

    Unfortunately not, as far as I can see. The code in UI builder that is running
    BuilderLibraryTreeItem
    for custom elements is passing "CustomCSharpElement" in as the
    iconName
    .
     
  5. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,203
    UI Builder did not yet learn how to allow users to customize the use of their custom C# elements inside the Builder. We are working towards first having a functionally complete Builder first before we expose extensibility features.

    For this specific question, what I'd do is set a default value for your text in the ButtonTranslatable's constructor. If no attribute is given in UXML, the default value will win. If an attribute is given in UXML, the UXML value will win.

    You can also extend the list of attributes shown in the Builder's inspector for your custom attribute by exposing a C# property. See this post for more details:
    https://forum.unity.com/threads/ui-builder-and-custom-elements.785129/#post-5225297
     
  6. ErnestSurys

    ErnestSurys

    Joined:
    Jan 18, 2018
    Posts:
    82
    Any updates on this issue?
     
  7. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,203
    This is still in the backlog. No update yet.

    One additional workaround you could try is to still set it in your constructor, but only if the existing value is empty or default. You'd get something close to the Button example.