Version: 2021.3
言語: 日本語
カスタムコントロールのカスタムスタイルを作成する
バインド可能な要素のリファレンス

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. Declare a custom element.
  2. BindableElement から要素を継承するか、IBinding インターフェースを実装します。
  3. INotifyValueChanged インターフェースを実装します。
  4. SetValueWithoutNotify() メソッドを INotifyValueChanged インターフェースに実装します。
  5. value プロパティアクセサーを INotifyValueChanged インターフェースに実装します。

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

When writing a custom inspectors you don’t have to explicitely bind a serialized object to the visual tree like in the editor windows examples above. This step is done implicitely after the CreateInspectorGUI method finishes. This automatic binding step is only performed at that time. If you add a field outside of a callback to the CreateInspectorGUI method, you will need to bind it manually. Otherwise it might fail to render or produce undefined visual results.

ベストプラクティス

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

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

条件 自動バインド時間 (バインディングパスが設定されていることが前提)
C# で 構築される InspectorElement コンストラクター の呼び出し中
A child element that is under the return value of CreateInspectorGUI() or CreatePropertyGUI() when those methods return After CreateInspectorGUI() or CreatePropertyGUI() returns
A child element that is under an element when Bind() or BindProperty() is called on the parent element During the Bind() or BindProperty() call
Other 自動バインディングはありません。要素またはその親の 1 つを手動でバインドする必要があります。

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

  • If you create a custom Editor or custom PropertyDrawer, set the elements’ binding paths instead of calling Bind() or BindProperty() on any visual elements that are in the visual tree by the end of the body of CreateInspectorGUI() or CreatePropertyGUI(). These elements are bound automatically after CreateInspectorGUI() or CreatePropertyGUI() returns. However, if you add any elements to the visual tree after that point, call Bind() or BindProperty() to bind them.
  • If you create any other type of UI, call Bind() or BindProperty() regardless of the time at which the elements get added to the visual tree. If you call Bind() or BindProperty() and bind multiple controls at the same time, set the binding path of each control and then call Bind() on the lowest-level parent element that encompasses all the controls. Bind() binds the element on which it’s called if it has a binding path and recursively binds all its child elements if they have binding paths. To prevent a negative performance impact, don’t bind a visual element with the Bind() method more than once.

その他の参考資料

カスタムコントロールのカスタムスタイルを作成する
バインド可能な要素のリファレンス