- Home /
Can you override/extend text property?
I'm looking for a way to override or extend the text property of a Text component.
What I mean by this is, every time I set my Text component like this:
myText.text = "hello world";
I want that to trigger another set of code, without explicitly calling those other functions.
Back in the Flash Actionscript days, I would extend the main class and keep its original intended behaviour using Super(). Is there something similar in Unity C# and how would I do it?
Yeah. @$$anonymous$$acDX and @FortisVenaliter are pointing you in the right direction. If at all possible, encapsulate framework-y stuff and proxy it to intercept events like this. I'll give you a third option for spice but, I warn you, theirs are the better road. $$anonymous$$ine is the "if you can't do it that way, then I guess you have to do it this way" way and it won't be instant.
I appreciate your and others' replies. It's going to take me a while to dig through the 3 or so flavours of solution here before marking an answer. Thanks!
Answer by MacDx · Sep 29, 2017 at 09:25 PM
Properties are basically just get and set methods for a field. You can't really make it "trigger" another set of code without explicitly calling it, any code or language feature that does it, will eventually call a function or a delegate, event, etc. under the hood, after the modification of the value.
My suggestion is to create a property inside the script that contains the myText field that calls that other set of code right after modifying the value of myText.text, something along these lines:
//This is the property
public string MyText
{
get
{
return myText.text;
}
set
{
myText.text = value;
//Here call your other set of code, I would suggest a method like this
//maybe if you want to do something with the new value
OnTextValueChanged(value);
}
}
This allows you to use it like this:
MyText = "newStringValue";
so that would update the value of myText.text and also "automatically" call your other set of code, passing "newStringValue" as a parameter to it.
Hope this helps!
In the end, this is what I went with. The obvious and simple. Since my code is already setting text, there is not much harm in making it a call to a new method, rather than overriding .text .
Honorable mention to @$$anonymous$$axGuernseyIII though for providing the technically correct anwer to "can you override/extend the text property" (option 2 in his answer below).
Answer by FortisVenaliter · Sep 29, 2017 at 09:27 PM
Well, this has nothing to do with Unity really, just C#.
I'm not 100% sure it can be done, but if it can, it would be something like this:
You'd define a new class deriving from Text (if Text is sealed, this won't work).
You use the "new" keyword to redefine the 'text' property's getter and setter, including your code, then applying the values to "base.text". For example:
public new String text { get { return base.text; } set { MyLogic(); base.text = value; } }
The 'text' property from Text is virtual so you could very well override it and apparently Unity will let you use the new class ins$$anonymous$$d of the Text class if you want, however, I$$anonymous$$O it isn't worth it to do if you won't extend the class significantly. All that he wants is just calling his desired behaviour after modifying the value, he can achieve that with a simple Set method or a property like I suggested.
Yeah, I tend to agree with you. The only problem is that the user could still write to the original text value through the inspector and bypass his logic. This way, it ensures it will always run. Unfortunately, a new Editor class will probably need to be written.
This is actually irrelevant. The built-in setter code is also bypassed by the TextEditor.
Since the property is virtual the only correct way is to override it in a derived class. Using "new" would result in inconsistent behaviour if you have a "Text" reference to your derived class. Overriding ensures that the actual code of the derived class is executed no matter if you have a reference to the base class or the derived class.
Since the whole source code is open source you can also modify the source directly and recompile your own version. Though for compatibility it's better to create a derived class if you really need additional functionality.
Answer by MaxGuernseyIII · Sep 29, 2017 at 10:18 PM
Okay. Here are two more options but both carry serious drawbacks. Their only advantage is that they allow you to sneak behavior into a mature system with a lot of coupling to Text.text.
Option 1: Observe and report
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
public class WatchTextAndRaiseEvent : MonoBehaviour
{
public Text ToWatch;
public UnityEvent OnChanged;
private string lastText;
void Start()
{
lastText = ToWatch.text;
}
void Update()
{
var newText = ToWatch.text;
if (newText != lastText)
OnChanged.Invoke();
lastText = newText;
}
}
Drawback: Imperfect timing. Depending on when Update is called, it will either raise the event in the same frame as the text change or the next one but it will never be in the call stack of the actual change. This could be obnoxious if you need to trace down why something isn't working the way you want.
Option 2: Override text property
using UnityEditor;
using UnityEngine.Events;
using UnityEngine.UI;
public class InterceptingText : Text
{
public UnityEvent OnChanged;
public override string text
{
get
{
return base.text;
}
set
{
OnChanged.Invoke();
base.text = value;
}
}
}
Drawback: Coupling and effort to make it work in the editor. You're inviting yourself to couple even-more-heavily to something you don't control. In the case of certain framework-y things, like this property, it may be that you can get away with that but it's a bad habit... like bending down to tie your shoes at the bus stop. It's usually not going to be a problem but, when it is, it can be a big one.
Furthermore, I couldn't instantly determine a way to make OnChanged editable in the inspector. Text does something funky. I'm afraid you might have to make a custom editor that includes the behavior of the editor for text.
Like I said in my comment, if possible, go with @MacDx's or @FortisVenaliter's approach of "encapsulate and intercept" and go with these if you absolutely must.
Your answer
![](https://koobas.hobune.stream/wayback/20220612135933im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
How to display text on a cube and how to change it dynamically? 2 Answers
How to read the format "Key: Value" 1 Answer