Version: 2022.1
言語: 日本語
カスタムインスペクターの作成
バインド可能な要素のリファレンス

SerializedObject のデータバインディング

データ バインディングは、MonoBehaviourstring プロパティなどの非 UI オブジェクトのプロパティを、TextField の value プロパティなどの UI オブジェクトのプロパティと同期します。バインディングは、プロパティとそれを変更するビジュアルコントロールの間のリンクを指します。

データバインディングを使用して、プロパティと特定のビジュアル要素との間で値を同期させます。そのため、UI で値が変更されたときに、イベントハンドラー を書く必要はありません。

ノート: SerializedObject のデータバインディングはエディターでだけ機能し、ランタイムには機能しません。

シリアル化の要件

シリアル化されたプロパティ にのみバインドする (関連付ける、紐づける) ことができます。つまり、ビジュアル要素をバインドできるのは、シリアル化システム と互換性のある以下のオブジェクトに限られます。

  • ユーザーが定義した ScriptableObject クラス
  • ユーザーが定義した MonoBehaviour クラス
  • Unity のネイティブのコンポーネントタイプ
  • Unity のネイティブのアセットタイプ
  • intboolfloat などの C# のプリミティブ型
  • Vector3ColorObject などの Unity のネイティブの型

値のバインディング

INotifyValueChanged インターフェースを実装したビジュアル要素の value プロパティのみをバインドすることができます。例えば、TextField.valuestring (文字列) にバインドすることはできますが、TextField.namestring にバインドすることはできません。

BindableElement から派生するか、IBindable インターフェースを実装するオブジェクトと任意のビジュアル要素の間でバインドすることができ ます。

ラグドールの作成

バインディングを作成するには、Bind() または BindProperty() のいずれかを呼び出します。

Bind() を呼び出す

Bind() を呼び出して、要素をSerializedObject にバインドすることができます。要素をバインドする前に,バインドパスを設定し SerializedObject を作成する必要があります.

バインディングの SerializedProperty に簡単にアクセスできない場合は、このメソッドを使用します。例として、C# スクリプトでバインディングを作成する を参照してください。

Bind() 拡張メソッドは、指定された bindingPath プロパティを持つビジュアル要素の階層全体を設定します。Bind() メソッドを、単一の要素またはバインドしたい階層の親に対して呼び出すことができます。例えば、Bind() をエディターウィンドウの rootVisualElement 上で呼び出すことができます。これにより、指定した bindingPath プロパティを持つすべての子要素がバインドされます。

Bind()Editor.CreateInspectorGUI() または PropertyDrawer.CreatePropertyGUI() のオーバーライドから呼び出さないようにしてください。これらのオーバーライドは、これらのメソッドが返すビジュアル要素で自動的に呼び出されます。

Unbind() を呼び出す

Unbind() メソッドは、要素とその直接および間接のすべての子要素の値の追跡を停止します。一般に、ユーザーが Inspector やエディターウィンドウを閉じるときに追跡が停止するため、Unbind() を呼び出す必要はありません。Unbind() は、要素の生存期間に異なるターゲットに要素をバインドする必要がある場合に呼び出します。

C# でコンストラクターを呼び出して InspectorElement を構築する場合、 コンストラクター呼び出し時にバインドが発生します。InspectorElement を構築した後でバインドし直す場合は、Unbind() を呼び出し、`Bind() を明示的に呼び出すか、親からのバインド操作でバインディングを作成する必要があります。

バインドパスの設定

Bind() を呼び出してバインディングを作成する場合、ビジュアル要素のバインディングパスをバインドしたいオブジェクトのプロパティ名に設定する必要があります。

例:

  • 以下のようなコンポーネントスクリプトがある場合

    using UnityEngine;
    
    public class MyComp : MonoBehaviour
    {
        [SerializeField]
        int m_Count;
    }
    

    ビジュアル要素を m_Count にバインドするには、バインドパスを m_Count に設定します。

  • ビジュアル要素を、ゲームオブジェクトの name プロパティ (m_Name) にバインドする場合は、バインドパスを m_Name に設定します。

バインディングパスは、UI Builder、UXML、または C# スクリプトで設定することができます。

BindProperty() を呼び出す

BindProperty() を呼び出して、要素を SerializedProperty に直接バインドすることができます。

SerializedProperty オブジェクトをすでに持っている場合、特に SerializedObject のプロパティを走査して動的に UI を構築する場合に、このメソッドを使用します。例として バインディングパスなしのバインド を参照してください。

ネストされたプロパティに要素をバインドする

ビジュアル要素をソースオブジェクトのネストされたプロパティにバインドすることができます。これを行うには、要素のバインディングパスと最初の先祖のバインディングパスを組み合わせます。この方法は、以下の要素で使用します。

例として、ネスト状のプロパティにバインド を参照してください。

値が変更されたときにコールバックを受け取る

バインドされたシリアル化されたプロパティが変更されたときにコールバックを受け取るバインディングを作成することができます。そのためには、TrackPropertyValue() 拡張メソッドを活用します。このメソッドは、任意の VisualElement で利用可能です。これは、提供された SerializedProperty が変更されたときに実行するコールバックを登録します。例として、シリアル化されたプロパティが変更されたときにコールバックを受け取る を参照してください。

また、バインドされたシリアライズオブジェクトのいずれかのプロパティが変更されたときにコールバックを受信するバインディングを作成することもできます。そのためには、TrackSerializedObjectValue() 拡張メソッドを活用します。これは、任意の VisualElement で利用可能です。これは、提供された SerializedProperty が変更されたときに実行するコールバックを登録します。例として、プロパティが変更されたときにコールバックを受け取る を参照してください。

カスタムエレメントをバインドする

カスタム要素を作成し、値のバインディング システムを通じて、シリアル化されたプロパティにバインドすることができます。

バインド可能なカスタム要素を作成するには、以下を行います。

  1. カスタム要素を宣言 します。
  2. BindableElement から要素を継承するか、IBinding インターフェースを実装します。
  3. INotifyValueChanged インターフェースを実装します。
  4. SetValueWithoutNotify() メソッドを INotifyValueChanged インターフェースに実装します。
  5. value プロパティアクセサーを INotifyValueChanged インターフェースに実装します。

例として、カスタムコントロールの作成とスタイル設定 を参照してください。

ノート: バインディングシステムでは、enum の SerializedPropertyType でサポートされている型にしか要素をバインドできないため、カスタムデータ型をカスタム要素に直接バインドすることはできません。つまり、クラスや構造体、例えばMyStruct という構造体を定義し、それをINotifyValueChanged<MyStruct> を実装する要素にバインドすることはできません。しかし、カスタムデータ型のシリアル化可能なネストされたプロパティにバインドすることはできます。これには多相シリアル化が含まれます (フィールドが [SerializeReference] 属性 を使用する場合)。例として、カスタムコントロールをカスタムデータ型にバインドする を参照してください。

ベストプラクティス

作成する UI の種類によって、バインドは様々なタイミングで発生します。これはバインド時間と呼ばれます。

以下の表では、操作の設定項目について説明します。

条件 自動バインド時間 (バインディングパスが設定されていることが前提)
C# で 構築される InspectorElement コンストラクター の呼び出し中
CreateInspectorGUI() または CreatePropertyGUI() メソッドが値を返すとき、その戻り値の下にある子要素 CreateInspectorGUI() または CreatePropertyGUI() が値を返した後。
Bind() または BindProperty() が親要素で呼び出されるとき、要素の下の子要素 Bind() または BindProperty() 呼び出しの間
Other 自動バインディングはありません。要素またはその親の 1 つを手動でバインドする必要があります。

バインドタイムに関して、バインディングを作成する際のベストプラクティスを以下に示します。

  • カスタム Editor またはカスタム PropertyDrawer を作成する場合は、CreateInspectorGUI() or CreatePropertyGUI() のボディの終わりまでに ビジュアルツリー 内にあるすべてのビジュアル要素について、Bind() または BindProperty() を呼び出す代わりに、要素のバインディングパスを設定します。 これらの要素は CreateInspectorGUI() または CreatePropertyGUI() が返された後に自動的にバインドされます。ただし、それ以降にビジュアルツリーに要素を追加する場合は、Bind() または BindProperty() を呼び出して要素をバインドします。
  • 他のタイプの UI を作成する場合は、要素がビジュアル ツリーに追加された時間に関係なく、Bind() または BindProperty() を呼び出します。 Bind() または BindProperty() を呼び出して、複数のコントロールを同時にバインドする場合は、各コントロールのバインディングパスを設定してからすべてのコントロールを含む最下位の親要素で Bind() を呼び出します。 Bind() は、バインディングパスがある場合は呼び出される要素をバインドし、その子要素にバインディングパスがあれば子要素をすべて再帰的にバインドします。パフォーマンスへの悪影響を防ぐには、ビジュアル要素を Bind() メソッドで複数回ビジュアル要素をバインドしないでください。

バインディングの例

データバインディングを使ったコード作成を学ぶには、以下の例を参照してください。

その他の参考資料

カスタムインスペクターの作成
バインド可能な要素のリファレンス