How to listen for Component property changes?

Hi,

I am feeling very home in unity, but have a tiny problem that I am sure there is a solution to - that I just can’t find.

I can’t figure out whether there is an elegant way to listen on property value changes done in the Inspector at runtime.

Example - some component with exposed property to be edited in the Inspector:

public class BootStrapperView : AView
{
  public bool debug = true; // exposed property that can be changed at runtime by Unity user
  private bool lastDebug ; // property duplicate to detect change :(

  public void Start()
  {
    // save initial value
    lastDebug = debug;
  }
  
  public void Update()
  {
    // per update check (expensive) per property (cumbersome) to catch changes made in Inspector
    if(lastDebug != debug)
    {
      // update model via controller 
      notifyDebugPropertyChange(this, lastDebug, debug);
      lastDebug = debug;
    }
  }
}

Any way to use C# properties, so I can code a setter?
Any way to get generic component event when the Inspector changes something?

Thanks in advance!

1 Like

I’m not sure of any way to track changes in values changed in the inspector. In C# you can create implicit accessors (the only problem is that these don’t show up in the inspector). This would allow you to create getters and setters to track variables in your code (it can also be used to make a variable read only by not including a setter).

public float foo{
   get{
      return _foo;
   }
   set{
      _foo = value;
      notifyDebugPropertyChange(this, lastDebug, debug); 
   }
}
private float _foo;

Hi Jeff,

Yes, that is what I want, and the properties not showing up is the problem.

I’m looking into making a serializable BoolProperty class that the Unity Inspector can show and edit, and I can listen on - but no success yet.
Not sure it is the best approach either…

That’s the best solution I know of; I personally have plans (someday) to create a replacement of the all the editor properties with one massive custom Editor class… see http://forum.unity3d.com/viewtopic.php?p=187649 for my proof-of-concept attempt.

Basically, I wish the Editor system allowed us to specify what we want visible and what it should look like with .NET Attributes… but those hooks don’t seem to exist or at least aren’t publicly available.

Good luck; I’d like to know what you figure out for a solution!

Thanks for the link.

I thought I could make some thin Editors - one per primitive e.g. float and bool - but that is not possible since there is a 1-to-1 relationship between a component and an editor.

Instead I am ending up in the same ally as you. I have created a generic editor that for now can introspect float and bool properties.

Here is how I define an editor per component:

using UnityEditor;

[CustomEditor(typeof(BootStrapperView))]
public class BootStrapperViewEditor : GenericEditor
{
}

Here is a component that gets it properties called when changing values in the Inspector:

using UnityEngine;
using System.Collections;

public class BootStrapperView : AView
{
	public float myFloat = 0;
	public float MyFloat
	{
		get	{ return myFloat; }
		set 
		{ 
			Debug.Log(MyFloat + " -> " + value);
			myFloat = value; 
		}
	}

	public bool enableDebugOnAwake = true;
	public bool EnableDebugOnAwake
	{
		get { return enableDebugOnAwake; }
		set 
		{
			Debug.Log(EnableDebugOnAwake + " -> " + value);
			enableDebugOnAwake = value; 
		}
	}
<SNIP>

And here is my ugly bloated generic editor doing introspection on my component:

using UnityEngine;
using UnityEditor;
using System.Reflection;
using System.Globalization;

/// <summary>
/// Generic editor for simple types.
/// 
/// Create a new editor for each component and inherit from this.
/// A public field named fooBar will have its property FooBar read/written.
/// 
/// Only supports float and bool - for now.
/// </summary>
public class GenericEditor : Editor
{

	public void OnInspectorGUI()
	{
		GUIStyle style = new GUIStyle();
		{
			style.alignment = TextAnchor.MiddleLeft;
			style.stretchWidth = true;
			RectOffset offset = new RectOffset();
			offset.left = 5;
			offset.right = 5;
			//style.padding = offset;
			style.fixedWidth = 200f;
			style.margin = offset;
		}

		System.Type targetType = target.GetType();
		PropertyInfo[] propertyInfos = targetType.GetProperties();
		FieldInfo[] fieldInfos = targetType.GetFields();

		// Algorithm with O(n^2) running time ahead, sorry!
		for (int i = 0; i < fieldInfos.Length; ++i)
		{
			FieldInfo fieldInfo = fieldInfos[i];
			string propertyName = fieldInfo.Name.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture);
			propertyName += fieldInfo.Name.Substring(1);

			for (int j = 0; j < propertyInfos.Length; ++j)
			{
				PropertyInfo propertyInfo = propertyInfos[j];
				System.Type propertyType = propertyInfo.PropertyType;
				System.Type fieldType = fieldInfo.FieldType;

				// Property of field fooBar MUST be named FooBar and use same type
				if (0 == propertyName.CompareTo(propertyInfo.Name)
					 fieldType.Equals(propertyType))
				{
					EditorGUILayout.BeginHorizontal();

					EditorGUILayout.BeginVertical();
					EditorGUILayout.PrefixLabel(fieldInfo.Name, style, style);
					EditorGUILayout.EndVertical();

					for (int k = 0; k < 8; ++k)
					{ // really clever code here, not!
						EditorGUILayout.BeginVertical();
						EditorGUILayout.Space();
						EditorGUILayout.EndVertical();
					}

					EditorGUILayout.BeginVertical();
					{
						if(fieldType.Equals(typeof(System.Boolean)))
						{
							System.Boolean currentValue = (System.Boolean)propertyInfo.GetValue(target, null);
							bool newValue = EditorGUILayout.Toggle(currentValue.Equals(true));
							if (currentValue != newValue)
							{
								propertyInfo.SetValue(target, newValue, null);
							}
						}
						else if(fieldType.Equals(typeof(System.Single)))
						{
							float currentValue = (float)propertyInfo.GetValue(target, null);
							float newValue = EditorGUILayout.FloatField(currentValue);
							if (currentValue != newValue)
							{
								propertyInfo.SetValue(target, newValue, null);
							}
						}
						else
						{
							string errorMessage = "type " + fieldType + "not supported yet!";
							EditorGUILayout.LabelField(errorMessage, "");
							Debug.LogWarning(errorMessage);
						}
					}
					EditorGUILayout.EndVertical();

					EditorGUILayout.EndHorizontal();
					break;
				}
			}
		}

		if (GUI.changed)
		{
			//Debug.Log("Gui changed");
			EditorUtility.SetDirty(target);
		}
	}
}

I would really like a future version of Unity to support properties. As for now I am stuck with the first of these two evils:

  • writing an editor class per component and maintaining a generic editor class, or
  • doing expensive change detections in the game code.

We solve the problem with a message system and higher-level abstractions. So instead of watching a single variable, a script can digest something like EnemyKilled or ItemSpawned. Some of our messages are fairly low-level and occur quite frequently, and others are things like game over messages that fire once a game.

So any word as to whether there are any plans to expose properties in the inspector? I realize that if ALL properties were to show up, we’d have a really bloated-looking transform inspector, for example. But I’m thinking just an additional attribute or something like:

[ShowInInspector]
public float MyVal
{
   get { return myVal; }
   set { myVal = value; }
}

That would make life SOOOOOOOOOOOOOO much easier!

2 Likes

Does anyone have any further information on this? We are a few versions and years since this thread. It would be very helpful to be able to have properties work or have a way that setting a value in the inspector can affect the scene or do simple validation without having to create editor classes.

If there is a better way to do this now, can someone kindly post a link to the thread or sample? thanks! :slight_smile:

I know, it’s an old post, but I solved this via OnValidate()

14 Likes

Or you can check Advanced Inspector in my signature. It support showing properties and parameter-less methods on the inspector.

Check out this answer that shows using proper MVVM architecture and listening to property changes in Unity3d. c# - MVVM Binding in Unity3d or Bind properties to compenents (controls) in Unity3d - Stack Overflow.

1 Like

@junedmmn , please please look at the post you’re replying to. It’s ELEVEN YEARS OLD. Dead and buried. Mountains have fallen and oceans dried up in that amount of time, and APIs have changed significantly. Don’t necropost.

1 Like

Please check dates when responding. Closed.