Version: Unity 6.0 (6000.0)
言語 : 日本語
ログレベルの定義
ランタイムデータバインディングの例

カスタムバインディングタイプの作成

カスタムバインディングタイプを作成して、ランタイムバインディングシステムを拡張できます。カスタムバインディングタイプを作成するには、クラスを作成し、CustomBinding クラスから継承します。

バインディングオブジェクトの登録と登録解除

CustomBindingIBinding インターフェースに似ており、1 つのインスタンスではなく複数のバインディングインスタンスを登録することができます。CustomBinding は拡張性のエントリーポイントで、バインディングを更新するための Update メソッドのみを提供します。ただし、以下のメソッドを実装して、バインディングが登録または登録解除された場合、および要素のデータソースコンテキストが変更されたときにコールバックを受け取ることができます。

データソースとデータソースパスの定義

バインディングタイプのデータソースとデータソースパスを定義するには、IDataSourceProvider インターフェースを実装します。バインディングシステムは、このインターフェースが提供する dataSourcedataSourcePath のプロパティを使用して、解決されたデータソースとデータソースパスを決定します。これらのプロパティは、階層から取得した値をオーバーライドするため “ローカル” と呼ばれます。ここで重要なのは、これらの “ローカル” プロパティを変更しても、要素自体やその子孫には影響しないということです。

更新トリガーの定義

デフォルトでは、バインディングシステムはフレームごとに CustomBinding インスタンスを更新します。

更新トリガーを定義するには、以下のメソッドを使用します。

  • MarkDirty:バインディングオブジェクトを dirty として設定し、次のサイクル中に更新されるようにします。
  • updateTrigger:この enum プロパティを使用して、バインディングの更新方法を変更します。
  • BindingResult:このメソッドを使用して、更新プロセスをカスタマイズします。BindingResult は、更新が成功したかどうかを示す構造体です。statusmessage が含まれています。

BindingResult には、statusmessage が含まれます。status として以下の値を使用できます。

  • Success: バインディングの更新に成功しました。バインディングインスタンスが定期的な更新を必要としない場合は、データソースが変更されるか、更新トリガーに基づいてバインディングインスタンスが明示的にダーティとしてマークされるまで、インスタンスは再度更新されません。
  • Failure: バインディングの更新に失敗しました。バインディングインスタンスが定期的な更新を必要としない場合は、データソースが変更されるか、更新トリガーに基づいてバインディングインスタンスが明示的にダーティとしてマークされるまで、インスタンスは再度更新されません。
  • Pending: バインディングの更新はまだ進行中です。バインディングインスタンスは、成功または失敗の応答を受け取るまで、自動的にダーティとしてマークされます。

BindingResult メソッドの Pending の結果を使用して、次のサイクルでバインディングオブジェクトを更新する必要があるかどうかを、バインディングシステムに通知できます。

このセクションでは、カスタムバインディングタイプを作成し、UI Builder、UXML、および C# でバインディングを設定する方法を例を挙げて説明します。

以下の例では、現在の時刻を表示するカスタムバインディングタイプを作成します。ラベルの text プロパティにバインドして、時計を作成できます。

using System;
using Unity.Properties;
using UnityEngine.UIElements;

[UxmlObject]
public partial class CurrentTimeBinding : CustomBinding
{
    [UxmlAttribute]
    public string timeFormat = "HH:mm:ss";

    public CurrentTimeBinding()
    {
        updateTrigger = BindingUpdateTrigger.EveryUpdate;
    }

    protected override BindingResult Update(in BindingContext context)
    {
        var timeNow = DateTime.Now.ToString(timeFormat);
        var element = context.targetElement;
        if (ConverterGroups.TrySetValueGlobal(ref element, context.bindingId, timeNow, out var errorCode))
            return new BindingResult(BindingStatus.Success);

        // Error handling
        var bindingTypename = TypeUtility.GetTypeDisplayName(typeof(CurrentTimeBinding));
        var bindingId = $"{TypeUtility.GetTypeDisplayName(element.GetType())}.{context.bindingId}";

        return errorCode switch
        {
            VisitReturnCode.InvalidPath => new BindingResult(BindingStatus.Failure, $"{bindingTypename}: Binding id `{bindingId}` is either invalid or contains a `null` value."),
            VisitReturnCode.InvalidCast => new BindingResult(BindingStatus.Failure, $"{bindingTypename}: Invalid conversion from `string` for binding id `{bindingId}`"),
            VisitReturnCode.AccessViolation => new BindingResult(BindingStatus.Failure, $"{bindingTypename}: Trying set value for binding id `{bindingId}`, but it is read-only."),
            _ => throw new ArgumentOutOfRangeException()
        };
    }
}

カスタムバインディングタイプを作成すると、UI Builder の Add binding ウィンドウに表示されます。UI Builder でバインディングを設定するには、Add Binding ウィンドウで Type リストから CurrentTimeBinding を選択します。

このバインディングに相当する UXML は以下のとおりです。

 <ui:Label text="Label">
    <Bindings>
        <CurrentTimeBinding property="text" />
    </Bindings>
</ui:Label>

このバインディングに相当する C# は以下のとおりです。

var label = new Label();
label.SetBinding("text",  new CurrentTimeBinding());

推奨ガイド

パフォーマンスを最適化するには、以下のヒントとベストプラクティスに従ってください。

  • 要素ごとのステートの使用を最小限にする: カスタムバインディングタイプで、要素ごとのステートへの依存を減らします。代わりに、可能な限り共有ステートまたはグローバルステートを活用し、パフォーマンスを向上させてメンテナンスをシンプルにします。
  • BindingUpdateTrigger.OnSourceChanged を使用する: ソースで変更が検出されたときにのみ更新が必要なバインディングタイプの場合は、updateTriggerBindingUpdateTrigger.OnSourceChanged に設定します。これにより、バインディングタイプが必要なときにのみ更新され、パフォーマンスが最適化されます。
  • 手動更新に BindingUpdateTrigger.WhenDirty を使用する: バインディングタイプを手動で更新し、即時の同期を必要としない場合は、updateTriggerBindingUpdateTrigger.WhenDirty に設定します。これにより、バインディングタイプが更新されたときに手動で制御できるようになり、柔軟な同期の制御が可能になります。
  • コールバックを活用する: 可能な場合は常に、Update コールバックの代わりに OnActivatedOnDeactivated、または OnDataSourceChanged のコールバックを使用してください。これらのコールバックは、特定のライフサイクルイベントでトリガーされるため、不要な更新が減り、効率が向上します。適切なコールバックを使用することで、バインディングタイプの動作を最適化し、必要なときに正確に更新を行うことができます。

追加リソース

ログレベルの定義
ランタイムデータバインディングの例