Datenbindung und Theme-Framework — MRTK3

Willkommen zur MRTK3-Datenbindung und Theme-Framework. Dieses Framework ist so konzipiert, dass visuelle Elemente leicht erstellt werden können, die dynamisch aufgefüllt und aktualisiert werden können, indem Daten aus einer oder mehreren Datenquellen bereitgestellt werden.

Was ist Datenbindung

Datenbindung ist der Prozess, der eine Verbindung zwischen der UX einer Anwendung (Ansicht) und den dargestellten Daten (Modell) herstellt. Angenommen, die Bindungseinstellungen sind korrekt und die Daten liefern die richtigen Benachrichtigungen. Wenn die Daten ihren Wert ändern, geben die an die Daten gebundenen Elemente die Änderungen automatisch wieder.

Beliebte Datenbindungsframeworks:

  • Delphi
  • Windows Presentation Framework (WPF .NET)
  • Windows Forms
  • Angular
  • Backbond
  • JavaFX-Bindungen

Windows Presentation Framework-Datenbindungsblockdiagramm

Datenbindung Windows Presentation Framework (WPF) Weitere Informationen finden Sie unter Datenbindung Übersicht - WPF.NET


MRTK-äquivalentes Blockdiagramm

MRTK equivalent block diagram


Entwurfsziele

  • Plattformübergreifend--überall bereitstellen
  • Unterstützen Sie jede Organisationsstruktur und den Ursprung von Datenquellen
  • Einfache Integration in bestehende oder Greenfield-Codebasen
  • Designer und Entwicklerfreundlich
  • Kann während des Anwendungslebenszyklus jederzeit aktiviert/deaktiviert werden
  • Unterstützt reale Unternehmensszenarien--Backend-DBs, komplexe UX-Prefab-Vorlagen
  • Einfache Anwendung auf bestehende nicht-MRTK UX-Komponenten und neue visuelle Elemente
  • Binden Sie jeden Datentyp, einschließlich Sprites, Bilder, Materialien, Animationen und Audioclips
  • Einfache Verbesserung der Funktionen ohne Berührung der bestehenden Codebasis
  • Effiziente Nutzung von CPU, RAM, GC und Frame-Zeit
  • Einfache Integration mit einer Vielzahl von lokalen oder Back-End-Datenquellen
  • Jede gleichzeitige Kombination von eingebetteten, Laufzeitstatus- und Back-End-Datenquellen
  • Effizienter Umgang mit Sammlungen beliebiger Größe für Listenpräsentation
  • Kombinierte Design- und Datenbindung für designfähige dynamische Datenelemente
  • Überprüfen und bearbeiten Sie Variablendaten auf offene Weise vor der Präsentation
  • Minimale Abhängigkeiten von anderen MRTK-Funktionen
  • Kompatibel mit MRTK v2 und MRTK3
  • Einfaches White Label und/oder Anwenden von Branding auf Aktienressourcen mit minimalem Aufwand

Wichtige Funktionen

  • Open-End-Datenquellen unterstützen jede Strategie für persistierte, Remote- oder RAM-Daten.
  • Open-End Datenverbraucher unterstützen jede Art von UX-Bindung und Designanforderungen.
  • Die automatische Ermittlung zwischen Datenquellen und Verbrauchern vereinfacht die Verknüpfung.
  • Optionale automatische Konfiguration aus einem Bindungsprofil
  • Entkoppeltes Datenmodell und Ansicht unterstützen MVC- und MVVM-Muster.
  • Virtualisierte Sammlungen mit Navigation durch Paging und Scrollen.
  • Prädiktive Prefetch von Sammlungsobjekten für die reibungslose Listennavigation.
  • Sammlungsobjekte können gruppiert und wiederverwendet werden, um GC zu reduzieren.
  • Kann zwischen Unterschieden in Daten und Ansicht von Keypath-Namespaces zugeordnet werden.

Aktuelle Funktionalität

1. Visualisieren von variablen Daten durch Datenverbraucher

Derzeit unterstützt:

  • TextMeshPro und TextMesh Text
  • Textformatvorlagen (für Design und Barrierefreiheit)
  • Sprite-Textur
  • Boolescher Trigger
  • Quad-Textur
  • Schriftartsymbole
  • Sammlungen: beliebig große Listen mit Prefabs, die mit variablen Daten gefüllt sind
  • Jeder andere Verbraucher, der die IDataConsumer-Schnittstelle unterstützt (direkt oder durch Basisklassen-Ableitungen)

2. Bereitstellen von variablen Daten unter Verwendung einee Vielzahl von Datenquellen:

  • JSON-Text (direkt oder per URL-Abruf)
  • Wörterbuch der variablen Datenelemente
  • Objekt - Knotenbasierte strukturierte Daten
  • Spiegelung eines beliebigen C#-Objekts
  • Programmgesteuerte veränderte Daten
  • Alle anderen Methoden, die die IDataSource-Schnittstelle unterstützen

3. Listenelementplatzierung zum Verwalten der visuellen Manifestation einer Liste

4. Listen-Paging, Scrollen und Virtualisierung

  • Daten werden nur abgerufen, wenn sie sichtbar sind oder verarbeitet werden
  • Unterstützt willkürlich große Back-End-Datensätze
  • Das Abrufen wird über mehrere Frames verteilt

5. Liste vorgefertigter Poolings

  • Prefabs werden wiederverwendet und aufgefüllt, um die GC- und Instanzierungszeit zu reduzieren.

6. Dynamische Anwendung von Designs auf Elemente zur Laufzeit


Funktionalität in der Roadmap

Zusätzlich zu dem bereits Verfügbaren haben folgende Funktionen die höchste Priorität:

1. Datenmanipulator-Pipelines

  • Konvertieren zwischen datenseitigen und ansichtsseitigen Werten
  • Lokalisierung (nahtlose Integration mit Unity-Lokalisierung)
  • Formatierung
  • Überprüfen

2. Prädiktiver Prefetch von Listenelementen für schnelleres/reibungsloseres Scrollen/Paging

3. Weitere Datenverbraucher

  • Festlegen einer öffentlichen Eigenschaft in einer Komponente
  • Aktivieren/Deaktivieren des Kontrollkästchens
  • Festlegen des Schiebereglerwerts
  • Festlegen eines Optionsfelds in einer Gruppe
  • Individuelle Materialeigenschaften wie z.B. Farbe festlegen

4. Design

  • Anzeigen der angewandten Designs im Editor, auch wenn die Anwendung nicht ausgeführt wird
  • Aktualisieren von Prefabs, um ein angewendetes Design darzustellen, sodass sie zum Standarddesign werden
  • Design / Formatvererbung

Begriff

  • Datenquelle – Jeder Anbieter von Daten, unabhängig vom Laufzeitzustand, lokal beibehalten oder aus einem Server abgerufen.
  • Datenquellenanbieter – Ein einfaches MonoBehaviour, das den Zugriff auf eine Datenquelle ermöglicht, die möglicherweise nicht im Unity-Szenendiagramm sichtbar ist.
  • Datenquellentyp – Ein eindeutiger Name, der der Datenquelle zugewiesen wird, so dass Datenverbraucher ihre gewünschte(n) Datenquelle(n) über den Namen angeben können.
  • Datenverbraucher – Jeder Verbraucher von Daten, die auf Datenänderungen reagieren möchten, in der Regel ein visuelles Element, aber nicht erforderlich. Der Zweck kann zum Beispiel darin bestehen, Aktionen auf der Grundlage von Änderungen der Datenwerte auszulösen.
  • Datenverantwortlicher – Ein Mechanismus zum Aufrufen einer Aktion mit dem aktuell zugeordneten Datenbindungswert, der als Parameter bereitgestellt wird.
  • Keypath – Eine Datenauswahl, die auf ein bestimmtes Objekt in einer Datenquelle verweist. So wie es derzeit implementiert ist, ist das Keypath-Format den JSON-Datenzugriffsfunktionen nachempfunden, um jede verschachtelte Kombination von Karten, Listen und Atomelementen zu entschlüsseln.
  • Lokaler Schlüsselpfad - Ein Schlüsselpfad (Keypath) auf der Seite des Datenverbrauchers, der dauerhaft in eine wiederverwendbare Prefab eingebettet werden kann. Durch Auflösen von Sammlungsentitäten und Schlüsselpfad-Mappern wird dies automatisch in einen vollständig aufgelösten Schlüsselpfad für ein bestimmtes Element in einer Sammlung konvertiert. Wenn sie keiner Sammlung zugeordnet sind, können diese entweder direkt einem Datum in der Datenquelle zugeordnet oder zuerst über einen Keypath-Mapper geändert werden.
  • Vollständig aufgelöster Schlüsselpfad - Ein vollständiger, absoluter Schlüsselpfad (Keypath), der einem bestimmten Objekt in einer Datenquelle zugeordnet ist. Für Elemente in einer Sammlung ist dies eine Kombination aus dem vollständig aufgelösten Schlüsselpfad für eine Sammlungsentität und einem relativen (lokalen) Schlüsselpfad für ein Datenelement dieser Sammlungsentität.

  • Keypath-Mapper - Optionaler Namespace-Mapper zwischen lokalen Schlüsselpfaden und Datenquellen-Feldnamen (z. B. "Link" <-> "URL").

  • Design – Eine Datenquelle, die eine Reihe verschiedener Ressourcen und Stile bereitstellt, die erforderlich sind, um eine bestimmte visuelle Ästhetik zu erreichen.

  • Item Placer - Ein DataConsumerCollection-Begleitprogramm, das für das Platzieren sichtbarer Elemente in eine Szene verantwortlich ist.

  • Datenobjektpool – Instanziierte, Standby-Prefabs bereit, um Daten für die Navigation mit niedriger GC-Liste zu füllen.

  • Listenvirtualisierung – Fähigkeit, beliebig große Listen zu füllen, darzustellen und darin zu navigieren.

  • Prädiktive Prefetch - Vorababruf von Daten und Auffüllen von Sammlungs-Prefabs für Objekte, die bald durch Scrollen/Paging angezeigt werden können.

  • Prädiktive Prefetch - Vorababruf von Daten und Auffüllen von Sammlungs-Prefabs für Objekte, die bald durch Scrollen/Paging angezeigt werden können.

Wichtige Konzepte

Data source

Eine Datenquelle ist ein beliebiger verwalteter Satz von Daten beliebiger Art(en) und beliebiger Komplexität, der verwendet werden kann, um Datenansichten über Datenkonsumenten zu füllen. Die von einer Datenquelle verwalteten Daten können statisch oder dynamisch sein. Alle Änderungen an Datenelementen werden an alle Datenverbraucher gemeldet, die registriert wurden, um Änderungsbenachrichtigungen zu erhalten.

Datenquellenanbieter

Eine einfache Schnittstelle mit einer einzigen Methode zum Abrufen einer Datenquelle. Diese ist so konzipiert, dass eine MonoBehavior-Skriptkomponente automatisch in der Spielobjekthierarchie von Datenanwenderkomponenten erkannt werden kann. Es ist nicht erforderlich, eine Datenquelle direkt auf dem Spielobjekt selbst zu implementieren. Dies ist nützlich, wenn ein vorhandenes MonoBehaviour von einer anderen Klasse abgeleitet werden muss und Mehrfachvererbung die Ableitung von DataSourceGOBase verhindert. Es ermöglicht auch, dass mehr Code keine Unity-Abhängigkeiten hat.

Datenquellenanbieter Singleton

Mit DataSourceProviderSingleton MonoBehaviour können Sie eine Datenquelle angeben, die automatisch erkannt werden kann, auch wenn sie sich nicht in derselben GameObject-Hierarchie befindet wie die Datenverbraucher, die auf sie hören wollen. Platzieren Sie einfach DataSourceProviderSingleton irgendwo in der Szene, und füllen Sie die Data Sources Eigenschaft mit allen Datenquellen auf, die von den Datenkonsumenten entdeckt werden sollen. Alternativ dazu werden Datenverbraucher ihre Eltern durchlaufen, um eine geeignete Datenquelle zu finden. Das bedeutet, dass Sie eine Datenquelle, die die gewünschten Daten bereitstellt, irgendwo in der übergeordneten Kette dieser Datenverbraucher einfügen können.

Schlüsselpfad (Zeichenfolge)

Ein Schlüsselpfad ist der Mechanismus zur eindeutigen Identifizierung von Informationen in einer Datenquelle.

Obwohl ein Schlüsselpfad ein beliebiger eindeutiger Bezeichner pro Datenelement sein kann, verwenden aktuelle Implementierungen einen logischen, vom Benutzer lesbaren Bezeichner, der die Navigationsposition der interessanten Daten relativ zum gesamten strukturierten Datensatz angibt. Es ist auf dem Konzept von Listen, Wörterbüchern und Grundtypen von Javascript modelliert. Schlüsselpfade sind syntaktisch korrekte Javascript-Anweisungen für den Zugriff auf Daten, die in JSON dargestellt werden können. Der Vorteil dieses Ansatzes besteht darin, dass er sowohl gut mit JSON als auch mit XML korreliert. Dies sind die beiden am häufigsten verwendeten Wege zur Informationsübertragung aus Back-End-Diensten.

Beispielschlüsselpfade:

  • Temperatur
  • contacts[10].firstName
  • Kontakte
  • contacts[10].addresses[3].city
  • [10].title
  • kingdom.animal.mammal.aardvark.diet.foodtypes.termites

Da es sich bei einem Schlüsselpfad um eine beliebige Zeichenkette ohne erforderliche Taxonomie handelt, können die eigentlichen Datenspezifikationen jede beliebige Methode sein, um zu beschreiben, welche Daten abgerufen werden sollen. XPath von XML ist ein Beispiel für ein funktionsfähiges Schlüsselpfadschema, das mit Datenquellen funktioniert. Solange Schlüsselpfade, die vom Datenverbraucher bereitgestellt werden, mit den von der Datenquelle erwarteten Schlüsselpfaden übereinstimmen, funktioniert alles. Darüber hinaus können KeyPath-Mappers implementiert werden, um zwischen verschiedenen Schemata zu übersetzen.

Auflösen eines Schlüsselpfads

Einen Schlüsselpfad aufzulösen bedeutet, zwei Schlüsselpfade zu kombinieren:

  1. Ein absoluter Schlüsselpfad, der beschreibt, wie auf eine bestimmte Teilmenge eines größeren Datensatzes zugegriffen wird, z. B. ein Eintrag in einer Liste mit vielen Einträgen.
  2. Ein partieller (relativer) Schlüsselpfad, der ein bestimmtes Datum innerhalb dieses Listen- oder Karteneintrags darstellt.

Dadurch ist es möglich, eine Teilmenge der Daten so zu behandeln, dass es egal ist, wo in einer größeren Datensatzhierarchie sie tatsächlich vorhanden ist. Die wichtigste Verwendung dieser Möglichkeit besteht darin, die Daten eines einzelnen Eintrags in einer Liste zu beschreiben, ohne sich sorgen zu lassen, welche Eingabe in dieser Liste auf die aktuelle Instanz verweist.

Da ein "vollständig aufgelöster" Schlüsselpfad immer von einer Datenquelle generiert und verbraucht wird und selten oder niemals von einem Datenverbraucher oder anderen externen Komponente geändert werden sollte, kann es eine beliebige Struktur haben, die für die Datenquelle sinnvoll ist. Wenn beispielsweise ein Prefab vorhanden ist, der einen Listeneintrag für ein Foto und dessen Titel, Aufnahmedatum und andere Attribute anzeigen soll, könnte der lokale Schlüsselpfad im Prefab wie folgt aussehen:

  • "photo_url"
  • "title"
  • "date_taken"
  • "description"

Die vollständig aufgelösten Schlüsselpfade für einen vorgefertigten Eintrag in einer Liste könnten wie folgt aussehen:

  • "f3cb1906-d8b3-489d-9f74-725e5542b55d/photo_url"
  • "f3cb1906-d8b3-489d-9f74-725e5542b55d/title"
  • "f3cb1906-d8b3-489d-9f74-725e5542b55d/date_taken"
  • "f3cb1906-d8b3-489d-9f74-725e5542b55d/description"

Key Path Mapper (IDataKeyPathMapper)

Eine Schlüsselpfad-Mapper ermöglicht es Datenquellen und Datenverbrauchern, verschiedene Namespaces und Konventionen für Schlüsselpfade zu verwenden und weiterhin zusammenzuarbeiten.

Ein Prefab für ein häufig verwendetes Element, z.B. eine Filmklappe zur Anzeige der Kontaktinformationen einer Person, kann variable Felder enthalten, die von Datenverbrauchern verwaltet werden. Um dies zu ermöglichen, benötigt der Bezeichner, der für irgendeinen variablen Aspekt des Prefabs verwendet wird, eine Möglichkeit, dem Bezeichner für das richtige Datum in der Datenquelle zuzuordnen, was in jeder Verwendung des Prefabs den Inhalt dieses variablen Elements bestimmt. Der Schlüsselpfad-Mapper ermöglicht dies.

Der Prefab kann mit verschiedenen Datenquellen verwendet werden, in denen die Daten in einer anderen Organisationsstruktur gespeichert werden und Feldnamen verwendet werden. Um einen Vorlagen-Prefab mit jeder Datenquelle zu verwenden, kann ein Schlüsselpfad-Mapper alle Unterschiede in der Organisation der Daten beheben.

Datenverbraucher (IDataConsumer)

Ein Objekt, das weiß, wie man Informationen, die von einer Datenquelle verwaltet werden, konsumiert und diese Daten zum Auffüllen von Datenansichten verwendet.

Datenverbraucher können sich mit einer Datenquelle registrieren, die über Änderungen an einem Datenelement benachrichtigt werden kann, das bei einem angegebenen Schlüsselpfad in einem Datensatz vorhanden ist. Wenn die angegebenen Daten geändert wurden (oder unter Verdacht stehen, sich geändert zu haben), wird der (oder die) Datenverbraucher benachrichtigt.

Sammlung von Verbraucherdaten

Eine Sammlung von Verbraucherdaten hat die hinzugefügte Möglichkeit, eine Liste ähnlicher Elemente zu verwalten. Diese Liste kann der gesamte von einer Datenquelle verwaltete Datensatz oder nur eine Teilmenge sein. In der Regel enthalten die Daten für jeden Eintrag in der Liste ähnliche Arten von Informationen, dies ist jedoch keine Voraussetzung. Datenquellen und Datenverbraucher können verschachtelte Listen unterstützen, z. B. eine Liste von Schlüsselwörtern, die jedem Foto in einer Liste der Fotos zugeordnet sind, die jeder Person in einer Kontaktliste zugeordnet sind. Der Schlüsselpfad für die Schlüsselwörter wäre relativ zum Foto, und der Schlüsselpfad für die Fotos wäre relativ zur Person, und der Schlüsselpfad der Person wäre entweder relativ zur nächstgelegenen übergeordneten Liste oder zum Stamm des Datensatzes.

Bei der Verarbeitung von Sammlungen wird jedem Datenverbraucher im Prefab, der für jedes Sammlungselement instanziiert wird, der korrekte aufgelöste Schlüsselpfad für den jeweiligen Eintrag in der Sammlung zugewiesen. Das wird dann verwendet, um den Schlüsselpfad für alle relativen (lokalen) Ansichtsdaten innerhalb dieser Prefab vollständig zu aufzulösen.

Placer für Datenerfassungselemente

Ein Sammlungsdatenverbraucher benötigt eine Möglichkeit, Benutzererfahrungen mit Listen aus sich wiederholenden visuellen Elementen zu befüllen, wie z.B. eine scrollbare Liste mit Produkten, Fotos oder Kontakten. Dies wird durch Zuweisen eines Elementplatzgebers zum Sammlungsdatenverbraucher durchgeführt. Dieser Elementplatzierer ist die Logik, die weiß, wie man Listenelemente anfordert, Prefabs akzeptiert, die mit variablen Daten gefüllt wurden, und sie dann dem Benutzer präsentiert. Üblicherweise werden sie in eine Liste eingefügt, die von einer UX-Layoutkomponente für Listen verwaltet wird.

Design

Das Design nutzt die gesamte Installation von Datenquellen und Datenverbrauchern. Es ist möglich, eine beliebige Hierarchie von GameObjects zu entwerfen, unabhängig davon, ob sie statisch sind oder dynamisch an andere Datenquellen gebunden sind. Dies ermöglicht die kombinierte Anwendung von Datenbindung und Design. Es ist sogar möglich, die Daten aus einer anderen Datenquelle zu designen.

Blockdiagramm und Datenfluss

MRTK theming data flow

MRTK Design

Das Design ist die Möglichkeit, die visuelle Ästhetik vieler UX-Elemente gleichzeitig zu ändern. In der Regel werden alle Daten, die für die Festlegung eines Designs benötigt werden, von einer einzigen Datenquelle bereitgestellt, z. B. einem skriptfähigen Objekt. Es ist auch möglich, dass Daten nach Bedarf bereitgestellt oder in logische Gruppen unterteilt werden, die auf ihrem Zweck basieren.

MRTK3 Theming

MRTK3-Design kombiniert mit Datenbindung

Datenbindung und Design können für ein einzelnes UX-Element koexistieren. Jedes einzelne UX-Element kann gleichzeitig designed und datengebunden werden. In diesem Szenario besteht der typische Ablauf darin, dass das aus einer Datenquelle stammende Datum verwendet wird, um den korrekten Schlüsselpfad des Designs abzuleiten. Dieser Schlüsselpfad wird dann verwendet, um ein Objekt aus der Datenquelle des Designs abzurufen. Dies ist in der Regel ein ScriptableObject-Profil, kann aber auch jede andere Datenquelle sein, die einen Schlüsselpfad auflösen kann.

Um die Konfiguration von Design und Datenbindung zu vereinfachen, können Bindungsprofile erstellt werden, die von einem BindingConfigurator zum Zeitpunkt der Instanziierung verarbeitet werden.

  • Eine BindingConfigurator verarbeitet ein Bindungsprofil, um die Assets innerhalb eines Prefabs zu bestimmen, die thematisiert werden sollen, und verknüpft sowohl gebundene Datenelemente als auch designfähige Elemente mit Schlüsselpfaden. Anschließend fügt es geeignete DataConsumers hinzu, um diese visuellen Elemente an die richtigen Schlüsselpfad-Selektoren zu binden, die verwendet werden, um auf bestimmte Daten in einem oder mehreren DataSources zu verweisen, die sich normalerweise außerhalb des Prefabs selbst befinden.
  • Designdaten werden durch DataSource bereitgestellt, das Daten für jeden im Bindungsprofil identifizierten Schlüsselpfad enthält.
  • Ein ThemeProvider Hilfsskript macht es einfach, ein ScriptableObject als DataSource Design zu verwenden.
  • Das Standard-UX-Design wird vom MRTK_UX_ThemeProfileScriptableObject bereitgestellt, das an ein DataSourceReflection Objekt gebunden ThemeProvider ist.

Theme Profile DataSource flow diagram

Eingebettete Datenquelle

Eine eingebettete Datenquelle ist in zwei Situationen sinnvoll:

  1. Wenn jede Instanz des Prefabs möglicherweise über verschiedene Designeinstellungen verfügt und eine eigene separate Datenquelle erfordert.
  2. Wenn alle Instanzen dieses Prefabs durch ein gemeinsames beibehaltenes Designprofil (z. B. ScriptableObject) gesteuert werden und über die eingebettete Datenquelle bereitgestellt werden können, sodass keine externen Abhängigkeiten vorhanden sind, die festgelegt werden sollen.

DataSourceReflection

Damit können Sie jede C#-Struktur oder -Klasse in ein DataSource verwandeln, indem Sie die Reflexion verwenden, um Schlüsselpfade auf Felder, Eigenschaften, verschachtelte Klassen, Arrays, Listen oder Wörterbüchern abzubilden. Es kann einem Unity ScriptableObject oder jeder anderen C#-Struktur oder -Klasse zugeordnet werden, in der Designdaten vorhanden sind. Das instanziierte Objekt, das die Daten enthält, kann zur Laufzeit Abhängigkeiten injiziert bekommen und geändert werden.

  1. Skriptfähiges Objekt: Nützlich für statische Designs, die für viele Prefabs freigegeben wurden.
  2. Nicht beibehaltene C#-Struktur oder Klasse: Nützlich für dynamische Laufzeitänderungen des Designs.

DataSourceJson

Wenn die Daten als json Text vorliegen, dann verwaltet dies die Zuordnung von Schlüsselpfaden zum json DOM. Binäre Assets können aus den Ressourcen, StreamingAssets oder sogar einer abgerufenen URL abgerufen werden.

DataSourceDictionary

Dies ist eine einfache Option, wenn eine rein flache Liste ausreicht, um den Bedarf zu decken, und für das schnelle Prototyping. Alle Designressourcen werden unterstützt, einschließlich Text, Unity-Ressourcen (z. B. Materialien, Sprites und Bilder), Ressourcen, StreamingAssets oder sogar externer Abruf über eine URL.

Benutzerdefiniert

Jede benutzerdefinierte Datenquelle, die die einfache IDataSource Schnittstelle implementiert oder von DataSourceBase oder DataSourceGOBase kann verwendet werden, um benutzerdefinierte Anforderungen zu erfüllen.

Design von UXComponents

Die standardmäßigen UXComponents-Steuerelemente, die im UXComponents-Paket bereitgestellt werden, sind für die Unterstützung der Designs konfiguriert. Es ist standardmäßig deaktiviert, ist jedoch einfach zu aktivieren.

Jedes Steuerelement, in der Regel auf dem obersten GameObject der Stamm-Prefab, hat ein Skript namens UXBindingConfigurator. Wenn dieses Skript aktiviert ist, ruft es die erforderlichen Datenbindungsskripts ab, um das Design zu aktivieren. Stellen Sie sicher, dass Sie auch das Datenbindungs- und Design-Paket importieren.

Hinweis auf TextMeshPro StyleSheets: Es ist derzeit nicht möglich, StyleSheets zum Formatieren des TextMeshPro Normalformats zu verwenden. Jede andere Formatvorlage, die in TextMeshPro's Standardformatvorlage enthalten ist, kann verwendet werden. Die Beispiele verwenden Body, um diese Einschränkung zu umgehen.

DataSourceThemeProvider

Das DataSourceThemeProvider MonoBehaviour kann verwendet werden, um ein ScriptableObject, das alle Verweise auf alle Designs enthält, als Datenquelle zu verwenden. Dies wird in der UXThemingExample-Szene gezeigt.

ThemeSelector

Das ThemeSelector MonoBehaviour ermöglicht es, mehrere ScriptableObject-Profile anzugeben und einfach zwischen ihnen zu wechseln. Eine beispielhafte Verwendung wäre, den Wechsel zwischen einem „dunklen“ und einem „hellen“ Design zu vereinfachen. Fügen Sie die SkriptableObjects Theme Profiles in der Regel zur Entwurfszeit hinzu. Ändern Sie dann zur Laufzeit die Current Theme Eigenschaft, um das Design zu ändern.

Datenverbraucher-Design

Das Design wird durch Datenverbraucher erreicht, insbesondere durch solche, die von DataConsumerThemeBase<T>, DataConsumerTextStyle und benutzerdefinierten DataConsumer-Klassen erben, die jeder Entwickler implementieren kann, um die Unterstützung für das Design zu verbessern.

Die DataConsumerThemeBase <T>-Basisklasse stellt Logik bereit, um eine ganze Zahl oder ein Schlüsseldatum aus einer primären Datenquelle zu verwenden, um den gewünschten Endwert aus einer sekundären Designdatenbank nachzuschlagen. Dies wird durch Zuordnen der Eingabedaten zu einem Designschlüsselpfad und dann durch Verwendung dieses Designschlüsselpfads zum Abrufen des Endgültigen Werts durchgeführt. Dadurch kann jedes Element gleichzeitig datengebunden und designed werden. Stellen Sie sich beispielsweise ein Statusfeld in einer Datenbank mit Status von "Neu", "Start" und "Fertig" vor, das durch Werte 0, 1 und 2 dargestellt wird. Jeder dieser Werte kann durch ein Sprite-Symbol dargestellt werden. Für die Datenbindung wird ein Wert von 0 bis 2 verwendet, um das gewünschte Sprite nachzuschlagen. Beim Design und der Datenbindung verweist das Designprofil auf die korrekte Liste von drei Sprites im Designprofil und dann wird der Wert von 0 bis 2 verwendet, um das richtige Sprite aus dieser Liste auszuwählen. Dadurch kann das Design dieser Symbole je nach Theme unterschiedlich gestaltet werden.

Wenn sowohl Laufzeitdesignen als auch dynamische Datenbindung zusammen verwendet werden, kann eine DataConsumerThemeHelper-Klasse in jeder von DataConsumerThemeBase abgeleiteten Klasse angegeben werden, um zu benachrichtigen, wenn sich ein Design geändert hat.

Das Austauschen von Designs zur Laufzeit erfolgt durch das Ersetzen der Daten in der thematischen Datenquelle durch einen neuen Datensatz, der in der gleichen Topologie des Datenobjektmodells angelegt ist. DataSourceReflection kann mit ScriptableObjects verwendet werden, wobei jedes Profil ein Design darstellt. Für alle MRTK Core UX-Steuerelemente ist das Designprofil ein ScriptableObject namens MRTK_UXComponents_ThemeProfile. Das Hilfsskript ThemeProvider.cs erleichtert die Verwendung dieses oder eines beliebigen ScriptableObject-Profils als Datenquelle.

Die Methode, ein Design auf dynamische Daten anzuwenden, kann in den meisten Fällen automatisch erkannt werden, oder es kann explizit angegeben werden.

Wenn das Datum verwendet wird, um das richtige Element aus der Designdatenquelle auszuwählen, lautet der Vorgang:

  • ein Datum aus der primären Datenquelle wird verwendet, um den richtigen Designschlüsselpfad auszuwählen oder zu erstellen
  • der Designschlüsselpfad wird verwendet, um einen Wert aus der Designdatenquelle abzurufen, die im DataConsumerThemeHelper angegeben ist
  • der abgerufene Designwert wird analysiert, um die richtige Abrufmethode automatisch zu erkennen.
  • das endgültige Datenelement des richtigen Typs (z. B. Material, Sprite oder Bild) wird dann unter Verwendung der automatischen Erkennungsmethode abgerufen.

Datentypen

Der erwartete Datentyp des Datums, das zum Abrufen des gewünschten Objekts verwendet wird, kann einer der folgenden sein:

Datentyp BESCHREIBUNG
AutoDetect Das Datum wird analysiert und die richtige Interpretation wird automatisch erkannt. Weitere Informationen finden Sie unter "Automatische Erkennung des Datentyps" weiter unten.
DirectValue Es wird erwartet, dass das Datum vom gewünschten Typ T (z.B. Material, Sprite, Bild) ist und direkt verwendet wird.
DirectLookup Ein integraler Index oder Zeichenfolgenschlüssel, der verwendet wird, um den gewünschten Wert in einer lokalen Nachschlagetabelle nachzuschlagen.
StaticThemedValue Statisches Designobjekt des richtigen Typs wird aus der Designdatenquelle unter dem angegebenen Designschlüsselpfad abgerufen.
ThemeKeypathLookup Ein integrierter Index oder Zeichenfolgenschlüssel wird verwendet, um den gewünschten Designschlüsselpfad zu suchen.
ThemeKeypathProperty Ein Zeichenfolgen-Eigenschaftsname, der an den Design-Basisschlüsselpfad angefügt wird, welcher im Design bereitgestellt wird.
ResourcePath Ein Ressourcenpfad zum Abrufen des Wertes aus einer Unity-Ressource (kann mit „resource://“ beginnen).
FilePath Ein Dateipfad zum Abrufen einer Unity-Streaming-Ressource /(kann mit „file://“ beginnen).

Datentyp automatisch erkennen

Autodetect analysiert die empfangenen Daten und entscheidet automatisch über die Abrufmethode. In der nachstehenden Tabelle stellt T den gewünschten Typ wie Material, Sprite, Image dar. Autodetect kann an zwei Stellen im Prozess auftreten:

  • Auf dem primären Datumswert selbst.
  • Über den thematischen Wert, der über das primäre Datum abgerufen wird.
Datumstyp Überlegungen Hat Designhelfer Verhalten
T J/N Direkt verwendet ohne Design
INT beliebige integrale Grundtypen oder int32-analysebare Zeichenfolgen Nein Wird als Index an abgeleitetes GetObjectByIndex(n) übergeben, um das N-te Objekt vom Typ T abzurufen.
INT beliebige integrale Grundtypen oder int32-analysebare Zeichenfolgen Ja Index, um den N-ten Design-Tastenpfad aus der lokalen Suche zu holen und dann das Designobjekt über die automatische Erkennung abzurufen.
Zeichenfolge Format: "resource://{resourcePath}" J/N resourcePath wird zum Abrufen von Unity-Ressourcen verwendet
Zeichenfolge Format: "file://{filePath} J/N filePath wird verwendet, um ein Streaming-Asset abzurufen
Zeichenfolge Sonstiges Nein Als Schlüssel an das abgeleitete GetObjectByKey() übergeben, um ein übereinstimmendes Objekt vom Typ T abzurufen.
Zeichenfolge Sonstiges Ja Schlüssel zum Abrufen des passenden Design-Schlüsselpfads aus der lokalen Suche und zum anschließenden Abrufen des thematischen Objekts über die automatische Erkennung.

Ein Beispiel zum Abrufen eines Designstatussymbols aus einer Datenbank mit einem numerischen Statuswert:

  1. Der Schlüsselpfad für ein Statussymbol in der Datenbank ist status.sprite_index.
  2. Der abgerufene Wert für status.sprite_index ist 2, was den Status "abgebrochen" bedeutet.
  3. Der N = 2 (in anderen Worten, dritte) Eintrag im DataConsumerSprite-Lookup wird auf "Status.Icons.Cancelled" gesetzt.
  4. Dies ist der Schlüsselpfad, der verwendet wird, um einen Wert aus der Datenquelle "Design" abzurufen.
  5. Der Wert für den Schlüsselpfad "Status.Icons.Cancelled" lautet "resource://Sprites/sprite_cancelled".
  6. Die automatische Erkennung bestimmt, dass das Symbol über eine Ressource abgerufen werden soll, die sich unter "Resources/Sprites/sprite_cancelled" befindet

TextMeshPro StyleSheets

Design ist in der Lage, TMPro-Stylesheets zu aktivieren. "TMP-Einstellungen" ScriptableObject diktieren, wo Stylesheets in den Ressourcen erwartet werden. Es handelt sich um die Eigenschaft "Standard-Schriftart-Asset => Pfad".

Stellen Sie sicher, dass Sie alle App-spezifischen StyleSheets im selben Unterpfad außerhalb von Resources platzieren. Wenn Sie sie anders organisieren möchten, stellen Sie sicher, dass Sie die „TMP-Einstellungen“ entsprechend aktualisieren.

Erstellen neuer, designfähiger UX-Steuerelemente

Wenn Sie neue UX-Steuerelemente entwickeln, ist es relativ einfach, sie designfähig zu machen. Soweit das Steuerelement Materialien, Sprites und andere Ressourcen verwendet, die bereits von anderen UX-Steuerelementen verwendet werden, geht es im Allgemeinen darum, die verschiedenen Spielobjekte auf erkennbare Weise zu benennen.

Es ist möglich, von den MRTK_UXCore_ThemeProfile zu erben und mehr designfähige Felder hinzuzufügen, oder Ihre Steuerelemente auf Ihr eigenes ScriptableObject zu verweisen. Es gibt nichts Magisches an den bereitgestellten; die Organisation des ScriptableObjects wird über C# Reflection die erforderlichen Schlüsselpfade für den Zugriff auf einzelne Datenelemente bestimmen.

Durch Hinzufügen eines BindingConfigurator.cs-Skripts zur obersten Ebene des neuen Steuerelements können Sie dann Ihr eigenes serialisiertes BindingProfile ScriptableObject angeben. Dadurch wird der erforderliche GameObject-Name für die benötigten KeyPath-Zuordnungen bereitgestellt, um Ihre designfähigen Elemente mit den Daten zu verknüpfen, die im Designprofil bereitgestellt werden. Dieses Skript fügt automatisch alle erforderlichen DataConsumerXXX-Komponenten zur Laufzeit hinzu, um das Design zu unterstützen, das Sie verwenden möchten.

Erste Schritte

Requirements (Anforderungen)

  • Unity 2020.3 LTS oder höher
  • TextMeshPro 2.1.4 oder höher

Beispielszenen

Sehen Sie sich zunächst die verschiedenen Beispielszenen für die Datenbindung im MRTK-Beispielpaket an und schauen Sie sich an, wie die verschiedenen MonoBehaviours aus der Datenquelle konfiguriert sind. Im Allgemeinen müssen Datenbindungsskripts nur auf der höchsten Ebene GameObject eines Prefabs oder eines verwandten Satz von UX-Elementen platziert werden.

Außerdem sind die Standardwerte für die meisten Anwendungsfälle sofort einsatzbereit, aber die offengelegten Eigenschaften bieten viel Flexibilität für die fortgeschritteneren Fälle.

Hinweis

Um das Design für die standardmäßigen MRTK-UX-Komponenten zu aktivieren MRTK_UX_DATABINDING_THEMING_ENABLED, muss das Symbol in den Spielereinstellungen definiert werden. Mit diesem Symbol wird sichergestellt, dass keine Leistungseinbußen auftreten, wenn das Design nicht benötigt wird.

Assets/DataBinding Example/Scenes/DataBindingExamples.scene

Diese Szene zeigt eine Vielzahl von Szenarien mit variablen Daten. Laden Sie einfach die Szene, und spielen Sie sie. Hierbei müssen noch einige Punkte beachtet werden:

  • Das Texteingabefeld von TextMeshPro-Komponenten enthält Variablen, die wie folgt aussehen: {{ firstName }}. Diese Markierungen werden direkt als lokale Schlüsselpfade verwendet.

  • Spielobjekte für Sprites und Text haben eine Art Datenverbraucher-Komponente, die den Empfang von Daten und die Aktualisierung von Ansichten verwaltet.

  • Ein einzelner Datenverbraucher kann von mehreren Komponenten desselben Typs geteilt werden, indem er in der GO-Hierarchie höher platziert wird.

  • Ein Datenverbraucher kann seine eigene Datenquelle finden, solange sie sich auf demselben Spielobjekt oder höher in der GO-Hierarchie befindet.

  • Ein übergeordnetes Spielobjekt hat eine Datenquellenkomponente, die Daten für alle untergeordneten Spielobjekte bereitstellt, die einen verwandten Satz variabler Informationen darstellen.

  • Ein Sammlungsdatenverbraucher gibt eine Prefab an, das selbst Datenverbraucher enthält, die zum Auffüllen dieses Prefabs mit Variablendaten verwendet werden.

Assets/UX Theming Example/Scenes/AudioTheming

In diesem Beispiel wird das Design verwendet, um AudioClips zwischen einem Satz für Piano und einer für Xylophone zu wechseln.

Assets/UX Theming Example/Scenes/BatteryLevelExample

In diesem Beispiel werden Design und Datenbindung kombiniert, um einen Akkustand sowohl als numerischer Wert als auch als Symbol anzuzeigen. Designen wird verwendet, um zwischen einem „ladenden“ und einem „nicht ladenden“ Design zu wählen. Es ist so konzipiert, dass die folgenden Ziele erreicht werden:

  • Alle visuellen Assets können in einer einzigen ScriptableObject vorhanden sein, die als Designprofil fungiert.
  • Die Anzahl der Sprites für „Laden“-Zustände kann von der Anzahl für „Nicht Laden“-Zustände abweichen.
  • Der Algorithmus zum Zuordnen des gemeldeten Batteriestands zu einem bestimmten Sprite kann nichtlinear sein und zwischen „Laden“- und „Nicht Laden“-Zuständen unterscheiden.
  • Alle visuellen Assets können in einer einzigen ScriptableObject vorhanden sein, die als Designprofil fungiert.
  • Die Anzahl der Sprites für Ladezustände kann von der Anzahl für den Ladezustand abweichen.
  • Der Algorithmus zum Zuordnen des gemeldeten Batteriestands zu dem Sprite kann nichtlinear sein und zwischen Lade- und Nicht-Ladezuständen unterscheiden.

Hinweis

Die Struktur dieser Demo ist kein gutes Beispiel für die Kombination von Design und Datenbindung. In einer Produktionsanwendung für eine ordnungsgemäße Trennung von Modell und Ansicht würde der tatsächliche Batteriezustand (Ladezustand und Ladezustand) in einer anderen Datenquelle bereitgestellt als die Ressourcen-Locators für die Sprites selbst.

Assets/UX Theming Example/Scenes/UXThemingExample

Dieses Beispiel demonstriert das Ändern des Themas einer gesamten Anwendung und demonstriert auch die Verwendung von DataSourceGODictionary Datenquelle zum Verwalten einer Vielzahl von Textinhalten, die in der UX angezeigt werden sollen. In einem umfassenderen Szenario werden die anderen flexibleren Datenquellentypen wahrscheinlich die erforderliche Flexibilität bieten, z.B. DataSourceReflection oder DataSourceGOJson.

Erstes Datenbindungsprojekt

Im Folgenden finden Sie ein einfaches Beispiel, mit dem Sie schnell beginnen können:

  1. Erstellen Sie eine neue Szene.
  2. Wählen Sie im Menü "Mixed Reality Toolkit" die Option Zu Szene hinzufügen und konfigurieren aus.
  3. Erstellen Sie ein leeres Spielobjekt, und benennen Sie es zu "Datenbindung" um. Fügen Sie eine DataSourceJsonTest-Komponente hinzu.
  4. Ändern Sie die URL im Inspektor in: https://www.boredapi.com/api/activity
  5. Fügen Sie dem Datenbindung-Spielobjekt ein UI -> TextMeshPro-Objekt hinzu. Es wird eine Canvas und dann ein "Text (TMP)"-Objekt hinzugefügt.
  6. Markieren Sie das TMP-Objekt (Text), und ändern Sie im Inspektor die Texteingabe in:

{{ activity }}. It's {{ type }}.

  1. Wählen Sie das Canvas-Objekt aus und fügen Sie ihm eine Datenverbraucher Text-Komponente hinzu.
  2. Führen Sie das Projekt aus. Alle 15 Sekunden wird eine andere Aktivität angezeigt.

Herzlichen Glückwunsch. Sie haben Ihr erstes Datenbindungsprojekt mit MRTK erstellt!

Schreiben einer neuen Datenquelle

Eine Datenquelle stellt Daten für einen oder mehrere Datenverbraucher bereit. Deren Daten können alles sein: algorithmisch generiert, im RAM, auf der Festplatte oder aus einer zentralen Datenbank abgerufen.

Alle Datenquellen müssen die IDataSource-Schnittstelle bereitstellen. Einige der grundlegenden Funktionen werden in einer Basisklasse namens DataSourceBase angeboten. Sie möchten wahrscheinlich von dieser Klasse abgeleitet werden, um die spezifischen Datenverwaltungsfunktionen für Ihre Anforderungen hinzuzufügen.

Um eine Datenquelle als Komponente auf ein Spielobjekt zu ablegen, ist ein anderes Basisobjekt namens DataSourceGOBase vorhanden, bei der GO für GameObject steht. Dies ist ein MonoBehavior, der auf ein GameObject als Komponente abgelegt werden kann. Es handelt sich um einen Thin-Proxy, der darauf ausgelegt ist, Arbeit an eine nicht Unity-spezifische Kerndatenquelle zu delegieren.

Eine Datenquelle kann die Möglichkeit bieten, Daten im Unity Editor zu bearbeiten. Wenn dies der Fall ist, kann die abgeleitete Klasse die gesamte Datenquellenlogik enthalten oder eine "Standard"-Datenquelle nutzen, aber auch Inspektorfelder oder andere Mittel zum Konfigurieren der Daten hinzufügen.

Schreiben eines neuen Datenverbrauchers

Ein Datenverbraucher wird benachrichtigt, wenn sich Daten geändert haben und aktualisiert dann einen Aspekt der Benutzererfahrung, wie z.B. den in einer TextMeshPro Komponente angezeigten Text.

Alle Datenverbraucher müssen die IDataConsumer-Schnittstelle bereitstellen. Einige der grundlegenden Funktionen werden in einer Basisklasse namens DataConsumerGOBase angeboten, bei der GO für GameObject steht.

Der Großteil der Arbeit eines Datenverbrauchers besteht darin, neue Daten anzunehmen und sie dann für die Präsentation vorzubereiten. Das kann so einfach sein, wie das Auswählen des richtigen Prefabs, oder es könnte bedeuten, dass mehr Daten aus einem Clouddienst wie einem Inhaltsverwaltungssystem abgerufen werden.

Schreiben eines Placers für ein Datenerfassungselement

Ein Datenerfassungs-Elementplatzierer ist dafür verantwortlich zu verwalten, welche Teile einer Sammlung derzeit sichtbar sind und wie diese sichtbare Sammlung präsentiert wird, unabhängig davon, ob es sich bei der Sammlung um eine kleine statische Liste oder eine riesige Datenbank mit Millionen von Datensätzen handelt.

Alle Elementplatzierer müssen die IDataCollectionItemPlacer-Schnittstelle bereitstellen. Einige der grundlegenden Funktionen werden in einer Basisklasse namens DataColletionItemPlacerGOBase angeboten. Alle Elementplatzierer sollten von dieser Klasse abgeleitet werden.

Bekannte Einschränkungen und fehlende Funktionen

  • Noch nicht in die Canvas-basierten Steuerelemente und scrollbaren Listen von Unity integriert.
  • Die Integration von .NET INotifyPropertyChanged ist noch nicht implementiert.
  • Beispielszenen, die Bilder von Flickr und trymrtk.com abrufen, funktionieren auf HoloLens aufgrund eines HTTPS-SSL-Fehlers in späteren Versionen von Unity nicht.
  • Zusätzliche Leistungsoptimierung.
  • Diese Version konzentriert sich auf die Datenpräsentation, nicht auf die Datenerfassung. Die MRTK UX-Steuerelemente sind noch nicht so verdrahtet, dass sie den Zustand in eine DataSource setzen.
  • Dynamische Änderungen an Listendaten werden vollständig aktualisiert, anstatt sie inkrementell zu aktualisieren.
  • Die Datenbearbeitungspipeline wurde noch nicht implementiert
  • Das Auffüllen aller UX-Komponenten auf einem Slate wird noch nicht vollständig unterstützt.
  • DataSourceJson-Knoten sollten IDataNode-Schnittstelle implementieren, um mit DataSourceObjects kompatibel zu sein.