Version: 2022.1
言語: 日本語
バインドされたプロパティが変更されたときにコールバックを受信する
ListView を使ってリストへバインドする

バインドされたプロパティが変更されたときにコールバックを受信する

バージョン: 2021.3 以降

この例では、バインドされたシリアル化されたオブジェクトのいずれかのプロパティが変更されたときに、コールバックを受け取る方法を示します。

例の概要

この例では、2 つのフィールドを持つカスタム Inspector を作成します。フィールドの値が特定の範囲外の場合、ユーザーに警告を発します。

この例で作成するすべてのファイルは、GitHub リポジトリ にあります。

要件

このガイドは、Unity エディター、UI Toolkit、および C# スクリプトに精通している開発者を対象としています。始める前に、以下をよく理解してください。

Weapon オブジェクトを作成する 

C# スクリプトを作成し、2 つのプロパティ m_BaseDamagem_HardModeModifier を持つ MonoBehaviour として Weapon クラスを定義します。

  1. Unity で任意のテンプレートでプロジェクトを作成します。

  2. Project ウィンドウに、callback-any-SerializedProperty-changes という名前のフォルダーを作成し、ファイルを保存してください。

  3. Weapon.cs という名の C# スクリプトを作成し、そのコンテンツを以下と置き換えます。

    using UnityEngine;
    
    namespace UIToolkitExamples
    {
        public class Weapon : MonoBehaviour
        {
            public const float maxDamage = 9999f;
    
            [SerializeField]
            float m_BaseDamage;
    
            [SerializeField]
            float m_HardModeModifier;
    
            public float GetDamage(bool hardMode)
            {
                return hardMode ? m_BaseDamage * m_HardModeModifier : m_BaseDamage;
            }
        }
    }
    

コールバックを受信するためのバインディングを作成する

Weapon のカスタム Inspector を定義する C# スクリプトを作成し、 TrackSerializedObjectValue() メソッドを使用して m_BaseDamage プロパティと m_HardModeModifier プロパティの変更を確認します。

  1. callback-any-SerializedProperty-changes フォルダー内に、Editor という名前のフォルダーを作成します。

  2. Editor フォルダーに、WeaponCustomEditor.cs という名の C# スクリプトを作成し、そのコンテンツを以下と置き換えます。

    using UnityEngine;
    using UnityEditor;
    using UnityEngine.UIElements;
    using UnityEditor.UIElements;
    
    namespace UIToolkitExamples
    {
        [CustomEditor(typeof(Weapon))]
        public class WeaponCustomEditor : Editor
        {
            // This is text used for the warning labels.
            const string k_NegativeWarningText =
                "This weapon has a negative final damage on at least 1 difficulty level.";
            static readonly string k_DamageCapWarningText =
                "This weapon has an excessive final damage that is capped to " + Weapon.maxDamage +
                " on at least 1 difficulty level.";
    
            // These are labels to warn users about negative damage and excessive damage.
            Label m_NegativeWarning, m_DamageCapWarning;
    
            public override VisualElement CreateInspectorGUI()
            {
                VisualElement root = new();
    
                // Create FloatFields for serialized properties.
                var baseDamageField = new FloatField("Base Damage") { bindingPath = "m_BaseDamage" };
                var modifierField = new FloatField("Hard Mode Modifier") { bindingPath = "m_HardModeModifier" };
                root.Add(baseDamageField);
                root.Add(modifierField);
    
                // Create warning labels and style them so they stand out.
                var warnings = new VisualElement();
                m_NegativeWarning = new(k_NegativeWarningText);
                m_DamageCapWarning = new(k_DamageCapWarningText);
                warnings.style.color = Color.red;
                warnings.style.unityFontStyleAndWeight = FontStyle.Bold;
                warnings.Add(m_NegativeWarning);
                warnings.Add(m_DamageCapWarning);
                root.Add(warnings);
    
                // Determine whether to show the warnings at the start.
                CheckForWarnings(serializedObject);
    
                // Whenever any serialized property on this serialized object changes its value, call CheckForWarnings.
                root.TrackSerializedObjectValue(serializedObject, CheckForWarnings);
    
                return root;
            }
    
            // Check the current values of the serialized properties to either display or hide the warnings.
            void CheckForWarnings(SerializedObject serializedObject)
            {
                // For each possible damage values of the weapon, determine whether it's negative and whether it's above the
                // maximum damage value.
                var weapon = serializedObject.targetObject as Weapon;
                var damages = new float[] { weapon.GetDamage(true), weapon.GetDamage(false) };
                var foundNegativeDamage = false;
                var foundCappedDamage = false;
                foreach (var damage in damages)
                {
                    foundNegativeDamage = foundNegativeDamage || damage < 0;
                    foundCappedDamage = foundCappedDamage || damage > Weapon.maxDamage;
                }
    
                // Display or hide warnings depending on the values of the damages.
                m_NegativeWarning.style.display = foundNegativeDamage ? DisplayStyle.Flex : DisplayStyle.None;
                m_DamageCapWarning.style.display = foundCappedDamage ? DisplayStyle.Flex : DisplayStyle.None;
            }
        }
    }
    

バインディングのテスト

  1. シーンで空のゲームオブジェクトを作成します。

  2. ゲームオブジェクトを選択します

  3. Inspector に Weapon コンポーネントを加えます。

  4. Weapon コンポーネントで、フィールドの値を変更します。

    • Base Damage または Base DamageHard Mode Modifier を掛けた値が負の値になると、警告メッセージが表示されます。
    • Base Damage または Base DamageHard Mode Modifier を掛けた値が 9999 より大きくなると、警告メッセージが表示されます。

その他の参考資料

バインドされたプロパティが変更されたときにコールバックを受信する
ListView を使ってリストへバインドする