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

Forcibly invalidating the UI

Discussion in 'UGUI & TextMesh Pro' started by Terra_, Aug 30, 2014.

  1. Terra_

    Terra_

    Joined:
    Jul 23, 2013
    Posts:
    8
    I'm using the technique described on this page: http://www.defectivestudios.com/devblog/garbage-free-string-unity/ to allow me use garbage free string manipulation in Unity.

    Briefly, I create a stringbuilder and use reflection to grab the internal string from it. I can then modify that string using stringbuilder.append() etc and simply pass the previously extracted string reference to wherever it's needed without needing to call ToString() on the stringbuilder object. For testing purposes, I'm incrementing a number in Update and appending the value to the previously described string.

    The problem is, short of enabling and disabling either the Canvas or Text component of the canvas object, there doesn't seem to be a way to force the UI to invalidate and redraw itself via code, I'm assuming this is because I'm reassigning the same string reference to the Text component whenever I need to change it and Unity assumes it hasn't changed. I can see the change to the string is reflected immediately in the Inspector window (also confirmed it in the debugger) however the actual text object in game is not redrawn unless I force Unity to redraw it via enabling/re-enabling the Text component, which doesn't seem like an efficient way of doing it. The article suggests tricking the system into updating the text via first setting it to some other value, "" for example, however this doesn't work with the new UI system. Is there any way I can get this system to work with the new UI without having to disable and re-enable the component whenever I change the value in the string? The relevant code is below:

    Code (csharp):
    1.  
    2. string myScoreString;
    3. public Text scoreText;  //scoreText is the Text component of the canvas I want to change
    4. private StringBuilder sbScore;
    5. int PlayerScore = 0;
    6.  
    7. public static string GetInnerString(this StringBuilder sb)
    8.   {
    9.   string str = (string)sb.GetType().GetField(
    10.   "_str",
    11.   System.Reflection.BindingFlags.NonPublic |
    12.   System.Reflection.BindingFlags.Instance).GetValue(sb);
    13.   //Optional: clear out the string
    14.   for (int i = 0; i < sb.Capacity; i++)
    15.   {
    16.   sb.Append(" ");
    17.   }
    18.   sb.Length = 0;
    19.   return str;
    20.   }
    21.  
    22. void Start () {
    23.   sbScore = new StringBuilder(32, 32);
    24.   myScoreString = sbScore.GetInnerString();  //string reference acquired from stringbuilder
    25.   }
    26.  
    27. void Update () {
    28.   PlayerScore++;
    29. //update the string via the stringbuilder
    30.   sbScore.Length = 0;
    31.   sbScore.Append(PlayerScore);
    32.   scoreText.text = "";
    33.   scoreText.text = myScoreString; //assign the string to the Text component
    34. }
    35.  
     
  2. Breyer

    Breyer

    Joined:
    Nov 10, 2012
    Posts:
    412
    Use setdiry text component have a lot *dirty function like setverticesdirty setalldirty etc. I cant remember if this is private or public though. In that case extend text component and create public wrapper. One of them should work. Btw to unity: i think there one dirty function with bool list would be better^^
     
    Last edited: Aug 30, 2014
  3. Terra_

    Terra_

    Joined:
    Jul 23, 2013
    Posts:
    8
    Thanks for the suggestion. I gave it a try, called all the different variants of SetDirty (All, Vertices, Material and Layout) and unfortunately none of them caused the text to redraw/update itself in this situation.
     
  4. JAKJ

    JAKJ

    Joined:
    Aug 17, 2014
    Posts:
    185
    Try Canvas.ForceUpdateCanvases.
     
  5. Terra_

    Terra_

    Joined:
    Jul 23, 2013
    Posts:
    8
    Sadly that doesn't work either in this case, thanks for the suggestion though.

    I think I might have to use two strings and just switch between them as needed to trick the canvas into updating.
     
  6. Breyer

    Breyer

    Joined:
    Nov 10, 2012
    Posts:
    412
    Strange. So there is last suggestion - use cachedtextgenerator to force rebuild text. I not suggest this previous because this is cannon against insect and maybe will be heavy performance
     
  7. Terra_

    Terra_

    Joined:
    Jul 23, 2013
    Posts:
    8
    Ah, cachedTextGenerator.Invalidate() does works in this situation, thanks.
     
  8. scone

    scone

    Joined:
    May 21, 2008
    Posts:
    244
    Ooh! I was looking for the solution here. I'd like to come up with some sort of pull request to submit to Unity to solve this problem inherently. Does this work in the latest version of Unity? I'll give this a try when I have the chance!

    By the way I'm the author of the original post ;)
     
  9. Deepscorn

    Deepscorn

    Joined:
    Aug 13, 2015
    Posts:
    25
    LayoutRebuilder.ForceRebuildLayoutImmediate or other methods of this class