Forcibly invalidating the UI

I’m using the technique described on this page: » Eureka! Garbage-free string manipulation in Unity!Defective Studios Devblog 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:

string myScoreString;
public Text scoreText;  //scoreText is the Text component of the canvas I want to change
private StringBuilder sbScore;
int PlayerScore = 0;

public static string GetInnerString(this StringBuilder sb)
  {
  string str = (string)sb.GetType().GetField(
  "_str",
  System.Reflection.BindingFlags.NonPublic |
  System.Reflection.BindingFlags.Instance).GetValue(sb);
  //Optional: clear out the string
  for (int i = 0; i < sb.Capacity; i++)
  {
  sb.Append(" ");
  }
  sb.Length = 0;
  return str;
  }

void Start () {
  sbScore = new StringBuilder(32, 32);
  myScoreString = sbScore.GetInnerString();  //string reference acquired from stringbuilder
  }

void Update () {
  PlayerScore++;
//update the string via the stringbuilder
  sbScore.Length = 0;
  sbScore.Append(PlayerScore);
  scoreText.text = "";
  scoreText.text = myScoreString; //assign the string to the Text component
}

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^^

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.

Try Canvas.ForceUpdateCanvases.

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.

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

Ah, cachedTextGenerator.Invalidate() does works in this situation, thanks.

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 :wink:

LayoutRebuilder.ForceRebuildLayoutImmediate or other methods of this class