📰

MRTK3 - DataBindingについて(Early Preview)

2022/12/14に公開

Mixed Reality Toolkit3の新機能「DataBinding」

コンテンツに利用するデータとそれを適用するデータをキーで紐づけることでバインドし動的にコンテンツ変更を実現する。別記事のThemingもData Bindingの派生機能として提供されている。

必要なパッケージ

  • com.microsoft.mrtk.data 1.0.0-pre.12

Data Binding概要

WPF等いくつかのフレームワークでも採用されているデータバインディングの概念をMRTK3の部品として実現したものがData Bindingになります。以下のようなデータソースとオブジェクトをキーで紐づけることで動的にコンテンツを操作することが可能になります。

引用元: Microsoft,データ バインディングとフレームワークのテーマ — MRTK3, https://learn.microsoft.com/ja-jp/windows/mixed-reality/mrtk-unity/mrtk3-data/packages/data/overview, 2022/11/29

Data Sourceに関連するもの

動的に使用するデータをデータソースとして管理するための部品は以下のものが提供されています。

種類 説明
DataSourceBase スクリプトで利用できるデータソースの基底クラス
DataSourceDictionary スクリプトで利用できる辞書形式のデータソース
DataSourceJson スクリプトで利用できるJson形式のデータソースの基底クラス
DataSourceGOBase コンポーネントとして利用できるデータソースの基底クラス
DataSourceGODictionary コンポーネントとして利用できる辞書形式のデータソース
DataSourceGOJson コンポーネントとして利用できるJson形式のデータソースの基底クラス
DataSourceObjects JSONやXMLで表現できるような構造化データを管理するデータソース
DataSourceReflection リフレクションを使用してオブジェクトの構造を決定するデータソース
DataSourceThemeProvider テーマの提供を簡素化するヘルパークラス
DataSourceDynamicList ランダムに生成される大きなリストを生成するシンプルなデータソースです。テストなどで利用可能

Data Consumerに関連するもの

Data ConsumerはData Sourceの情報を実際のコンテンツに反映する際に利用する部品群です。例えば、データソース内のテキスト情報をコンテンツ内のTextコンポーネントに反映したい場合などはDataConsumerTextを利用します。DataConsumerTextは内部でコンテンツ内のTextコンポーネントのリストを保持しており、DataSourceの情報とText内に記述されているキー情報を照合して情報の置換えを行います。

種類 説明
DataConsumerAudioClip 配下のAudioClipをDataSourceのバインド先として管理するコンポーネント
DataConsumerBooleanEvents バインドされた変数の更新に基づくUnityEventの呼び出しを可能にする。データソースのBoolean値でイベントを発生させたり、状態変更を検出。
DataConsumerCollection 配列要素の情報を管理するコンポーネント
DataConsumerCommandDispatcher このコンシューマにバインドされたデータソースに連動したコマンドをディスパッチする。配列などの複数要素を持つデータソースに対して編集や削除といったアクションを組み入れたい場合に使用する。
DataConsumerGOBase コンポーネントとして利用できるData Consumersの基底クラス
DataConsumerImageQuadFromUrl URLの情報から画像をダウンロードしQuadに表示するためのコンポーネント
DataConsumerImageSpriteFromUrl URLの情報から画像をダウンロードしSpriteに表示するためのコンポーネント
DataConsumerImageTextureFromUrl URLの情報から画像をダウンロードしTextureに表示するためのコンポーネント
DataConsumerMaterial 配下のMaterialをDataSourceのバインド先として管理するコンポーネント
DataConsumerSprite 配下のSpriteをDataSourceのバインド先として管理するコンポーネント
DataConsumerSpriteLookup 配下のSpriteをDataSourceのバインドキーでフィルターして管理するコンポーネント
DataConsumerText 配下のText(TextMeshPro, UnityEngine.UI.Text)をDataSourceのバインド先として管理するコンポーネント
DataConsumerTextStyle 配下のText(TextMeshPro, UnityEngine.UI.Text)のスタイルをDataSourceのバインド先として管理するコンポーネント
DataConsumerThemeHelper Themingで利用するスタイル適用などを支援するためのヘルパー

Data Bindingを便利に使うためのHelper

種類 説明
CollectionItemIdentifier コレクションの中の一つの項目の値として機能するクラス
DataCollectionEventsGOBase GameObjectの仮想基底クラスで、以下のようなサブクラスを作成することが可能です。Unity エディタインスペクタで「ドラッグ&ドロップ可能」であり、他のゲームオブジェクトのコンポーネントとして追加することができるサブクラスを作成することができます。ゲームオブジェクトのコンポーネントとして追加することができます。
DataCollectionEventsHandler DataCollectionEventsGOBaseのサブクラスで、すべてのイベントを公開。DataConsumerCollectionを組み合わせると、DataConsumerCollectionで表示している情報の状態によって発生するイベントを利用できます。これを利用するとデータの先頭に来ると「次へ」ボタンを表示したりといったことが可能になります。
DataKeyPathMapperDictionary スクリプトとして利用できるデータバインディング時に使用するキーの別名を管理するためのクラスです
DataKeyPathMapperGODictionary コンポーネントとして利用できるデータバインディング時に使用するキーの別名を管理するためのクラスです
DataNodeObject IDataNode インターフェースを実装した汎用 DOM 形式のデータノード
DataObjectPool オブジェクトの再利用に使用できるオブジェクトのデータプール。
DataParser Data Consumer内のキー値を抽出するためのクラス
DataSourceProviderSingleton Singltonのクラスを作成するためのヘルパークラス
ThemeSelector Themingで使用。複数のテーマ設定を管理し切り替える機能を提供する
TruncateString 文字列の切り捨てのためのユーティリティ

サンプル1 - DataSourceGODictionaryを使った文字の置き換え

Unityプロジェクトを作成しMRTK3を導入する

基本的な手順は以下の記事を参考に設定してください。

https://zenn.dev/miyaura/articles/32dbaf7256fef4

https://zenn.dev/miyaura/articles/be65665439f0d4

Data Bingingに必要なパッケージを導入する

必要なパッケージは以下のものになりますので、Mixed Reality Feature Toolでインポートしてください。

https://learn.microsoft.com/ja-jp/windows/mixed-reality/develop/unity/welcome-to-mr-feature-tool

  • com.microsoft.mrtk.data 1.0.0-pre.12

Data Sourceを準備する

まず、辞書形式のデータを保持できる[DataSourceGODictionary]を準備します。
[Hierarchy]で空オブジェクトを作成し、[Inspector]で[DataSourceGODictionary]を追加します。

[DataSourceGODictionary]に以下の設定を行います。

  • Data Source Type : data
  • Key Path Values
    • key : UserName, value : TestUser
    • key : Message, value : Hello

Data Sourceを反映するテキストを準備する

次に実際にDataSourceの情報を使ってテキストを変更してみたいと思います。先ほど作ったGameObjectの配下に[Text - TextMesh Pro]を追加します。TextMesh ProのScaleを(0.01,0.01,0.01)に変更し、テキストを「{{ Message }}, {{ UserName }}」と入力します。
{{ [Key Path] }}でData Source内のキーを検索し、その値で置き換える動作になります。

Data Consumer を追加します。

最後にData Sourceに情報をオブジェクトに反映するために、Data Consumerを追加します。
Data Sourceと同じGameObjectに[Data consumer Text]を追加します。[Data consumer Text]は子要素のオブジェクトを対象にテキストとしてkeypathが定義されているかどうかを自動的に探索するようになっています。

この状態で実行すると[DataSourceGODictionary]の情報が反映されます。

サンプル2 - DataConsumerCollectionを使ったオブジェクトによるリスト表示

DataSourceCollectionをDataSourceとして活用するとあらかじめ作成したPrefabにDataSourceの情報を反映しながら要素数分オブジェクトを生成して表示することができます。リストとして表示するオブジェクトも先ほどのDataConsumerをりようして作成することでカード式のリストなども容易に作成することができます。

Unityプロジェクトを作成しMRTK3を導入する

基本的な手順は以下の記事を参考に設定してください。

Data Bingingに必要なパッケージを導入する

必要なパッケージは以下のものになりますので、Mixed Reality Feature Toolでインポートしてください。

https://learn.microsoft.com/ja-jp/windows/mixed-reality/develop/unity/welcome-to-mr-feature-tool

  • com.microsoft.mrtk.data 1.0.0-pre.12

Data Sourceを準備する

今回は配列情報を扱うためにJsonデータを利用するDataSourceGOJsonを使ってみたいと思います。このくらいは基底クラスとして機能しており以下の情報があります

  • Webリクエストを発行しJsonデータを受信する
  • JsonデータをDataSourceとして割り当てる。

Jsonデータをどのように取得するかはデータ次第となるため使いやすい形でカスタマイズできるようになっています。今回はURLがない場合Inspectorで設定したJsonテキストで処理するというものになります。

// Copyright (c) 2022 Takahiro Miyaura
// Released under the MIT license
// http://opensource.org/licenses/mit-license.php
using Microsoft.MixedReality.Toolkit.Data;

public class DatasourceDemoJson : DataSourceGOJson
{
    private readonly string json = "{\"title\": \"Deta Binding\",\"description\": \"Data Binding is amazing!\"}";
    public string URL;

    public void Start()
    {
        if (!string.IsNullOrEmpty(URL))
            StartCoroutine(StartJsonRequest(URL));
        else
            SetJson(json);
    }
}

上記のコンポーネントを作成し[Hierarchy]タブで空のGameObjectに追加します。追加したGameObjectに先ほど作ったDatasourceDemoJsonを追加します。パラメータは以下の通り設定します。

  • Data Source Type : data
  • URL : Jsonデータを取得するURL

用意したJsonは以下のようなものです。子要素は100個ほど用意しました。
1要素にタイトル、詳細、画像を情報として持っています。これをカード式のレイアウトをもつオブジェクトに張り付けていきます。

{
	"title": "MRTK3 Sample Json Data",
	"description": "MRTK3 sample for Data binding",
	"details": [
		{
			"title": "MRTK3 Sample Image00",
			"description": "This is Sample Info No.00",
			"imageUrl": "https://Hoge.mrtk/images/mrtk00.jpg"
		},
		{
			"title": "MRTK3 Sample Image01",
			"description": "This is Sample Info No.01",
			"imageUrl": "https://Hoge.mrtk/images/mrtk00.jpg"
		},...
	]
}

リストとして表示する子要素をPrefabで作成する。

次にJsonでリストデータを展開する際に表示する子要素となるオブジェクトをPrefabで作成します。今回用意したJsonデータは以下のキーとデータを保持します。これにあったPrefabを用意します。

  • title : テキスト形式の文字列
  • description : テキスト形式の文字列
  • imageUrl : 画像イメージ

それぞれData Consumerを利用して作成します。テキスト系には[Data Consumer Text]、画像は[Data Consumer Image Quad From Url]を使用しました。[Data Consumer Image Quad From Url]はkeypathで指定されたURL形式の値を使ってWebリクエストを行いダウンロードした画像をQuadに描画します。

最初に空のGameObjectを作成し[Data Consumer Text]コンポーネントを追加します。

背景パネルの追加

子要素として背景用のBackplateを追加します。
空のGameObjectを追加し、[Mesh Fileter]、[Mesh Renderer]を追加します。それぞれ以下のパラメータを充てると標準の背景と同じパネルを構築することが可能です。

  • MeshFilter.Mesh : rounded_edge
  • MeshRenderer.Materials : MRTK_Backplate_10mm_Gradient

タイトルと詳細のテキスト領域の作成

次にJsonデータの[title],[description]を表示するためのテキストを追加します。それぞれTextMeshProで構築します。

  • title用の設定
    • position(0,0.17,-0.001)
    • width : 20
    • Height : 5
    • scale : (0.003,0.003,0.003)
    • text : {{ title }}

  • description用の設定
    • position(0.0108,-0.008,-0.001)
    • width : 40
    • Height : 15
    • scale : (0.002,0.002,0.002)
    • text : {{ description }}

先ほど親要素にDataConsumerTextを割り当てているのでこの2つのオブジェクトはData Souceによる変更対象となります。

画像の表示エリアの作成

最後に画像の表示エリアを作成します。子要素にQuadを追加します。Quadには画像を割り当てたいので[DataConsumerImageQuadFromUrl]を追加してJsonデータ内のURLから画像をダウンロードするように変更します。

* position(-0.07,0,-0.001)
* scale : (0.04,0.04,0.01)
* DataConsumerImageQuadFromUrl.KeyPath : imageUrl

以上で子要素を表示するオブジェクトの作成が完了です。これをPrefab化しておきましょう。

Data Consumer を追加します。

今回はリスト表示を行うので[Data Consumer Collection]を利用します。
Data Sourceを割り当てたオブジェクトの下に空のオブジェクトを作成し、[Data Consumer Collection]を追加します。

コンポーネントの設定は以下の部分を変更しています。

  • Collections Key Path : details(Jsonデータの配列要素を持つキー)
  • Item Prefab : Detail(先ほど作った子要素のPrefab)

Collections Key Pathには今回作成したJsonで配列を返す要素を作っているのでその設定になります。このようにJsonをデータソースにした場合はJsonのキーを直接指定する形になります。階層が深い場合はピリオド区切りでつなげていくことが可能です。例えば、{{ details[0].title }}と記載したテキストを用意すると、detailsの0番目の要素のtitleの値が反映されるようになっています。あまりに階層が深く扱いが難しい場合はDataSourceをカスタムして可読性を上げたりといったことも可能だと思います。

{
	"title": "MRTK3 Sample Json Data",
	"description": "MRTK3 sample for Data binding",
	"details": [
		{
			"title": "MRTK3 Sample Image00",
			"description": "This is Sample Info No.00",
			"imageUrl": "https://Hoge.mrtk/images/mrtk00.jpg"
		},
		{
			"title": "MRTK3 Sample Image01",
			"description": "This is Sample Info No.01",
			"imageUrl": "https://Hoge.mrtk/images/mrtk00.jpg"
		},...
	]
}

きれいに配置するための設定

上記の設定だけで実行することは可能ですが、生成されるオブジェクトが無秩序に配置されてしまいます。このような生成されたオブジェクトを整列して配置したい場合は[Data Collection Item Placer Offset]を利用します。先ほど作ったDataConsumerCollectionと同じオブジェクトに追加します。

一度に表示するオブジェクト数、配置の仕方については以下の情報で調整します。

設定項目 説明
Item Ofest Paddingを含めた1要素のオフセット値(オブジェクトサイズ+Padding)
X Count X軸方向の要素数
Y Count Y軸方向の要素数
Z Count Z軸方向の要素数

データ送りを実現する

上記までの対応で、配列要素をきれい整列して動的に表示することが可能になります。ただし、表示できる要素数を超えた場合はデータ送りをしてすべての要素をみたくないですか?そういった機能も提供されています。[Data Collection Item Placer Offset]にはデータを送りやページングの機能が提供されています。例えば、コレクションの上部にデータ送り用のボタンを用意し以下のメソッドを呼び出すことで、表示されている情報を切り替えることができます。

設定項目 説明
MoveToPreviousItem 要素を1つ戻す
MoveToNextItem 要素を1つ進める
PageBackward 前ページへ
PageForward 次ページへ

以下のボタンを押すと要素を1つ戻すことができる実装例です。

さらに[Data Collection Item Placer Offset]に[Data Collection Events Handler]を設定することで、表示されているデータの状態に応じて様々なイベントを発生させることができます。

以下は、表示しているデータが先頭、最後尾によって、ページ送りのボタンの表示/非表示を制御する例です。

[Data Collection Events Handler]にはこれ以外にも様々なイベントが利用できます。

設定項目 説明
Attach データがアタッチされた場合に発生
CollectionAtEnd データの最後に来た場合に発生
CollectionAtStart データの最初に来た場合に発生
CollectionCanGoBackward 1要素戻ることができる場合に発生
CollectionCanGoForward 1要素進むことができる場合に発生
CollectionChanged データコレクションが変更された場合に発生
CollectionContextSwitch
CollectionEmpty データが空になった場合に発生
CollectionInMiddle データの中央に来た場合に発生
CollectionNotEmpty データが空でない場合に発生
CollectionPagedBackward ページを戻すことができる場合に発生
CollectionPagedForward ページを進めることができる場合に発生
CollectionScrolledBackward スクロールを戻すことができる場合に発生
CollectionScrolledForward スクロールを進めることができる場合に発生
Detach データがデタッチされた場合に発生
EndPlacement 配置が完了した場合に発生
ItemPlaced アイテムを配置した場合に発生
StartPlacement 配置を開始した場合に発生

参考リンク

Discussion