【Unity】【UI Toolkit】バインドしたプロパティの変更をトラッキングする

UnityのUI Toolkitでバインドしたプロパティの変更をトラッキングする方法についてまとめました。

Unity 2022.2.19

UI Toolkitにおけるバインド

UI Toolkitでは、以下の記事のようにしてシリアライズされた値とUI要素をバインドすることができます。

light11.hatenadiary.com

いま、バインドした要素が変更された時に何かしらの処理をしたたいケースを考えます。

SerializedPropertyの変更をトラッキングする

値の変更をトラッキングするには、以下のようにVisualElement.TrackPropertyValueを使います。

using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;

public sealed class Example : EditorWindow
{
    private TextField _textField;

    public void CreateGUI()
    {
        _textField = new TextField("Object Name");
        rootVisualElement.Add(_textField);
        Bind(Selection.activeObject);
    }

    private void OnSelectionChange()
    {
        Bind(Selection.activeObject);
    }

    [MenuItem("Window/Example")]
    public static void ShowWindow()
    {
        GetWindow<Example>();
    }

    private void Bind(Object obj)
    {
        if (obj != null)
        {
            var so = new SerializedObject(obj);
            var property = so.FindProperty("m_Name");
            _textField.Unbind(); // トラッキングする前にUnbindしておく
            _textField.BindProperty(property);
            _textField.TrackPropertyValue(property, OnNameChanged); // トラッキング
            OnNameChanged(property);
        }
        else
        {
            _textField.Unbind();
            _textField.value = "";
        }
    }

    private void OnNameChanged(SerializedProperty property)
    {
        Debug.Log("Name Changed : " + property.stringValue);

        if (property.stringValue.Contains(" "))
            _textField.style.backgroundColor = Color.red;
        else
            _textField.style.backgroundColor = StyleKeyword.Null;
    }
}

今回は前節で紹介した記事のEditorWindowに、名前のチェック処理を加えました。
名前に半角スペースが入っていたらテキストフィールドを赤くしています。

テキストフィールドを赤く

SerializedObjectの変更をトラッキングする

SerializedObjectバインディングしている場合には、同じように、TrackSerializedObjectValueを使うことで値の変更をトラッキングできます。

using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;

public sealed class Example : EditorWindow
{
    private TextField _textField;

    public void CreateGUI()
    {
        _textField = new TextField("Object Name")
        {
            bindingPath = "m_Name" // SerializedObjectとバインドするためここでパスを入力しておく
        };
        rootVisualElement.Add(_textField);
        Bind(Selection.activeObject);
    }

    private void OnSelectionChange()
    {
        Bind(Selection.activeObject);
    }

    [MenuItem("Window/Example")]
    public static void ShowWindow()
    {
        GetWindow<Example>();
    }

    private void Bind(Object obj)
    {
        if (obj != null)
        {
            var so = new SerializedObject(obj);
            rootVisualElement.Unbind(); // トラッキングする前にUnbindしておく
            rootVisualElement.Bind(so);
            rootVisualElement.TrackSerializedObjectValue(so, OnValueChanged); // トラッキング
            OnValueChanged(so);
        }
        else
        {
            rootVisualElement.Unbind();
            _textField.value = "";
        }
    }

    private void OnValueChanged(SerializedObject so)
    {
        Debug.Log("Name changed: " + so.targetObject.name);
        var nameProperty = so.FindProperty("m_Name");

        if (nameProperty.stringValue.Contains(" "))
            _textField.style.backgroundColor = Color.red;
        else
            _textField.style.backgroundColor = StyleKeyword.Null;
    }
}

参考

docs.unity3d.com

docs.unity3d.com