Freigeben über


Datenbindungs- und Designframework — MRTK3

Willkommen beim MRTK3-Datenbindungs- und Designframework. Dieses Framework soll das Erstellen visueller Elemente vereinfachen, die zur Laufzeit 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 Benutzeroberfläche (Ansicht) einer Anwendung und den dargestellten Daten (Modell) herstellt. Angenommen, die Bindung verfügt über die richtigen Einstellungen und die Daten stellen die richtigen Benachrichtigungen bereit. Wenn die Daten ihren Wert ändern, spiegeln die an die Daten gebundenen Elemente automatisch Änderungen wider.

Beliebte Datenbindungsframeworks:

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

Datenbindungsblockdiagramm für Windows Presentation Framework

Datenbindung von Windows Presentation Framework (WPF) Weitere Informationen finden Sie unter Übersicht über die Datenbindung – WPF.NET


MRTK-äquivalentes Blockdiagramm

MRTK-äquivalentes Blockdiagramm


Entwurfsziele

  • Plattformübergreifend – überall bereitstellen
  • Unterstützung jeglicher Organisationsstruktur und Herkunft von Datenquellen
  • Einfache Integration in vorhandene oder Greenfield-Codebasen
  • Designer und entwicklerfreundlich
  • Kann jederzeit während des Anwendungslebenszyklus aktiviert/deaktiviert werden
  • Unterstützung realer Unternehmensszenarien – Back-End-DBs, komplexe UX-Prefab-Vorlagen
  • Einfache Anwendung auf vorhandene Nicht-MRTK-UX-Komponenten und neuartige visuelle Elemente
  • Binden eines beliebigen Datentyps, einschließlich Sprites, Bildern, Materialien, Animationen und Audioclips
  • Einfach zu erweiternde Funktionen, ohne vorhandene Codebasis zu berühren
  • Effiziente Nutzung von CPU, RAM, GC und Framezeit
  • Einfache Integration in eine Vielzahl von lokalen oder Back-End-Datenquellen
  • Jede gleichzeitige Kombination aus eingebetteten Datenquellen, Laufzeitzustand und Back-End-Datenquellen
  • Effizientes Verarbeiten von Sammlungen beliebiger Größe für die Listenpräsentation
  • Kombiniertes Design und Datenbindung für designbare dynamische Datenelemente
  • Überprüfen und Bearbeiten von Variablendaten auf offene Weise vor der Präsentation
  • Minimale Abhängigkeiten von anderen MRTK-Funktionen
  • Kompatibel mit MRTK v2 und MRTK3
  • Einfache White-Label- und/oder Branding-Anwendung auf Bestandsressourcen mit minimalem Aufwand

Wichtige Features

  • Open-End-Datenquellen unterstützen jede persistente, Remote- oder RAM-Datenstrategie.
  • Open-End-Datenconsumer unterstützen alle UX-Bindungs- und Designanforderungen.
  • Die AutoErmittlung zwischen Datenquellen und Consumern vereinfacht die Verknüpfung.
  • Optionale automatische Konfiguration aus einem Bindungsprofil
  • Entkoppelte Datenmodelle und Ansichten unterstützen MVC- und MVVM-Muster.
  • Virtualisierte Sammlungen mit Navigation über Paging und Bildlauf.
  • Prädiktives Vorabrufen von Sammlungselementen für eine reibungslose Listennavigation.
  • Sammlungsobjekte können in einem Pool zusammengefasst und wiederverwendet werden, um die GC zu reduzieren.
  • Kann zwischen Unterschieden in Daten und Anzeigen von Keypath-Namespaces zuordnen.

Aktuelle Funktionalität

1. Visualisieren von Variablendaten über Datenconsumer

Derzeit unterstützt:

  • TextMeshPro und TextMesh-Text
  • Text-Stylesheets (für Design und Barrierefreiheit)
  • Spritetextur
  • Boolescher Trigger
  • Quad-Textur
  • Schriftartsymbole
  • Sammlungen: Listen beliebiger Größe mit Prefabs, die mit Variablendaten aufgefüllt sind
  • Alle anderen Consumer, die die IDataConsumer-Schnittstelle unterstützen (direkt oder über Basisklassen-Ableitungen)

2. Bereitstellen von Variablendaten mithilfe verschiedener Datenquellen:

  • JSON-Text (direkt oder per URL-Abruf)
  • Wörterbuch variabler Datenelemente
  • Objekt: Knotenbasierte strukturierte Daten
  • Reflektion eines beliebigen C#-Objekts
  • Programmgesteuert geänderte Daten
  • Jede andere Methode, die die IDataSource-Schnittstelle unterstützt

3. Listenelementplatzierung zum Verwalten der visuellen Manifestation einer Liste

4. Auflisten von Paging, Bildlauf und Virtualisierung

  • Daten werden nur abgerufen, wenn sie sichtbar oder in Bearbeitung sind.
  • Unterstützt beliebig große Back-End-Datasets
  • Beim Abrufen wird ein Lastenausgleich für mehrere Frames durchgeführt.

5. Auflisten von Prefab-Pooling

  • Prefabs werden wiederverwendet und neu aufgefüllt, um die GC- und Instanziierungszeit zu verkürzen.

6. Dynamisches Anwenden von Designs auf Elemente zur Laufzeit


Funktionalität in der Roadmap

Zusätzlich zu den bereits verfügbaren Funktionen sind die wichtigsten Prioritäten für weitere Funktionen:

1. Datenmanipulatorpipelines

  • Konvertierung zwischen Datenseiten- und Ansichtsseitenwerten
  • Lokalisierung (nahtlose Integration mit Unity-Lokalisierung)
  • Formatierung
  • Überprüfung

2. Prädiktives Listenelementvorruf für schnelleres/reibungsloseres Scrollen/Paging

3. Mehr Datenverbraucher

  • Festlegen einer beliebigen öffentlichen Eigenschaft für eine Komponente
  • Aktivieren/Deaktivieren des Kontrollkästchens
  • Festlegen des Schiebereglerwerts
  • Festlegen eines Optionsfelds in einer Gruppe
  • Einzelne Materialeigenschaften, z. B. Festlegen der Farbe

4. Design

  • Anzeigen von Designs, die im Editor angewendet werden, auch wenn die Anwendung nicht ausgeführt wird
  • Aktualisieren von Prefabs, um ein angewendetes Design widerzuspiegeln, sodass es zum Standarddesign wird
  • Design-/Stilvererbung

Begrifflichkeiten

  • Datenquelle : Jeder Anbieter von Daten, unabhängig davon, ob es sich um den Laufzeitzustand handelt, lokal beibehalten oder von einem Server abgerufen wird.
  • Datenquellenanbieter : Ein einfaches MonoBehaviour, das Zugriff auf eine Datenquelle bietet, die möglicherweise nicht im Unity-Szenendiagramm verfügbar gemacht wird.
  • Datenquellentyp : Ein eindeutiger Name, der der Datenquelle zugewiesen ist, sodass Datenconsumer ihre gewünschten Datenquellen anhand des Namens angeben können.
  • Datenconsumer : Jeder Consumer von Daten, der auf Datenänderungen reagieren möchte, ist in der Regel ein visuelles Element, aber nicht erforderlich. Der Zweck kann beispielsweise darin sein, Aktionen basierend auf Datenwertänderungen auszulösen.
  • Datencontroller : Ein Mechanismus zum Aufrufen einer Aktion mit dem aktuell zugeordneten datengebundenen Wert, der als Parameter bereitgestellt wird.
  • Keypath : Eine Datenauswahl, die auf ein bestimmtes Objekt in einer Datenquelle verweist. Wie derzeit implementiert, wird das Keypath-Format nach JSON-Datenaccessoren modelliert, um eine geschachtelte Kombination aus Karten, Listen und atomaren Elementen zu entschlüsseln.
  • Lokaler Schlüsselpfad : Ein Schlüsselpfad auf Seiten des Datenverbrauchers, der dauerhaft in ein wiederverwendbares Prefab eingebettet werden kann. Durch auflösen von Sammlungsentitäten und Keypath-Mappern werden automatisch in einen vollständig aufgelösten Schlüsselpfad für ein bestimmtes Element in einer Auflistung konvertiert. Wenn sie keiner Auflistung zugeordnet sind, können diese entweder direkt einem Datum in der Datenquelle oder über einen Keypath Mapper zugeordnet werden.
  • Vollständig aufgelöster Schlüsselpfad : Ein vollständiger, absoluter Schlüsselpfad, der einem bestimmten Objekt in einer Datenquelle zugeordnet ist. Für Elemente in einer Auflistung ist 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 : Optionale Namespacezuordnung zwischen lokalen Schlüsselpfaden und Datenquellenfeldnamen (z. B. "link" <–> "URL").

  • Design : Eine Datenquelle, die eine Reihe verschiedener Ressourcen und Stile bereitstellt, die für eine bestimmte visuelle Ästhetik erforderlich sind.

  • Item Placer : Ein DataConsumerCollection-Begleiter, der für das Platzieren sichtbarer Elemente in einer Szene verantwortlich ist.

  • Datenobjektpool : Instanziierte Standby-Prefabs, die mit Daten für die Navigation mit niedriger GC-Liste gefüllt werden können.

  • Listenvirtualisierung : Möglichkeit zum Auffüllen, Präsentieren und Navigieren in Listen mit beliebig großer Größe.

  • Prädiktiver Prefetch : Vorabrufen von Daten und Auffüllen von Sammlungs-Prefabs für Elemente, die möglicherweise bald durch Scrollen/Paging angezeigt werden.

  • Prädiktiver Prefetch : Vorabrufen von Daten und Auffüllen von Sammlungs-Prefabs für Elemente, die möglicherweise bald per Bildlauf/Paging angezeigt werden.

Wichtige Konzepte

Datenquelle

Eine Datenquelle ist ein beliebiger verwalteter Satz von Daten beliebiger Art und Komplexität, die zum Auffüllen von Datenansichten über Datenconsumer verwendet werden kann. Die von einer Datenquelle verwalteten Daten können statisch oder dynamisch sein. Änderungen an Datenelementen werden allen Datenconsumern gemeldet, die sich registriert haben, um Änderungsbenachrichtigungen zu erhalten.

Datenquellenanbieter

Eine einfache Schnittstelle, die über eine einzelne Methode zum Abrufen einer Datenquelle verfügt, ist so konzipiert, dass eine MonoBehavior-Skriptkomponente in der Spielobjekthierarchie von Datenconsumerkomponenten automatisch ermittelt werden kann. Es ist nicht erforderlich, eine Datenquelle direkt für das Spielobjekt selbst zu implementieren. Dies ist nützlich, wenn ein vorhandenes MonoBehaviour von einer anderen Klasse abgeleitet werden muss und die Mehrfachvererbung verhindert, dass von DataSourceGOBase abgeleitet wird. Außerdem kann mehr Code keine Unity-Abhängigkeiten aufweisen.

Datenquellenanbieter Singleton

MonoBehaviour DataSourceProviderSingleton ermöglicht es, eine Datenquelle anzugeben, die automatisch ermittelt werden kann, auch wenn sie sich nicht in derselben GameObject-Hierarchie wie die DataConsumer befindet, die darauf lauschen möchten. Platzieren Sie den DataSourceProviderSingletonan einer beliebigen Stelle in der Szene, und füllen Sie die Data Sources Eigenschaft mit allen Datenquellen auf, die von Datenconsumern ermittelt wurden. Alternativ können Datenconsumer ihre übergeordneten Elemente durchlaufen, um eine geeignete Datenquelle zu finden. Dies bedeutet, dass Sie eine Datenquelle platzieren können, die die gewünschten Daten an einer beliebigen Stelle in der übergeordneten Kette dieser Datenconsumer bereitstellt.

Schlüsselpfad (Zeichenfolge)

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

Obwohl ein Schlüsselpfad ein beliebiger eindeutiger Bezeichner pro Datenelement sein kann, verwenden aktuelle Implementierungen einen logischen benutzerdefinierten Bezeichner, der die Navigationsposition der relevanten Daten relativ zum gesamten strukturierten Dataset angibt. Es basiert auf dem JavaScript-Konzept von Listen, Wörterbüchern und Grundtypen. 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 gut mit JSON und XML korreliert, die die beiden am häufigsten verwendeten Mittel zum Übertragen von Informationen aus Back-End-Diensten sind.

Beispiel für Schlüsselpfade:

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

Da ein Schlüsselpfad eine beliebige Zeichenfolge ohne erforderliche Taxonomie ist, können die tatsächlichen Datenspezifizierer eine beliebige Methode sein, um zu beschreiben, welche Daten abgerufen werden sollen. XPath von XML ist ein Beispiel für ein praktikables Schlüsselpfadschema, das mit Datenquellen funktioniert. Solange die vom Datenconsumer bereitgestellten Schlüsselpfade mit den von der Datenquelle erwarteten Schlüsselpfaden konsistent sind, funktioniert alles. Darüber hinaus können Key Path Mappers implementiert werden, um zwischen verschiedenen Schemas zu übersetzen.

Auflösen eines Schlüsselpfads

Das Auflösen eines Schlüsselpfads bedeutet, dass zwei Schlüsselpfade kombiniert werden:

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

Dies ermöglicht es, eine Teilmenge der Daten so zu behandeln, dass es keine Rolle spielt, wo sie in einer größeren Datasethierarchie tatsächlich vorhanden ist. Die wichtigste Verwendung dieser Funktion besteht darin, die Daten eines einzelnen Eintrags in einer Liste zu beschreiben, ohne sich Gedanken darüber machen zu müssen, auf welchen Eintrag in dieser Liste der aktuelle instance verweist.

Da ein "vollständig aufgelöster" Schlüsselpfad von einer Datenquelle generiert und genutzt wird und selten von einem DataConsumer oder einer anderen externen Komponente geändert wird, kann er eine beliebige Struktur aufweisen, die für die Datenquelle sinnvoll ist. Wenn beispielsweise ein Prefab vorhanden ist, um einen Listeneintrag für ein Foto und dessen Titel, Aufnahmedatum und andere Attribute anzuzeigen, 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 Prefab-Eintrag in einer Liste können 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"

Schlüsselpfadzuordnung (IDataKeyPathMapper)

Mit einer Schlüsselpfadzuordnung können Datenquellen und Datenconsumer unterschiedliche Namespaces und Konventionen für Schlüsselpfade verwenden und weiterhin zusammenarbeiten.

Ein Prefab für ein häufig verwendetes Element, z. B. ein Slate zum Anzeigen der Kontaktinformationen einer Person, kann variable Felder enthalten, die von Datenconsumern verwaltet werden. Zur Verwendung benötigt der bezeichner, der für einen variablen Aspekt des Prefabs verwendet wird, eine Möglichkeit, dem Bezeichner für das richtige Datum in der Datenquelle zuzuordnen, der bei jeder Verwendung des Prefabs den Inhalt dieses Variablenelements bestimmt. Die Schlüsselpfadzuordnung macht dies möglich.

Das Prefab kann mit verschiedenen Datenquellen verwendet werden, in denen die Daten in einer anderen Organisationsstruktur gespeichert sind und Feldnamen verwendet werden. Um ein Vorlagen-Prefab mit jeder Datenquelle zu verwenden, kann eine Schlüsselpfadzuordnung alle Unterschiede bei der Organisation der Daten auflösen.

Datenconsumer (IDataConsumer)

Ein -Objekt, das weiß, wie von einer Datenquelle verwaltete Informationen genutzt und diese Daten zum Auffüllen von Datenansichten verwendet werden.

Datenconsumer können sich bei einer Datenquelle registrieren, um über Änderungen an einem Datenelement benachrichtigt zu werden, das an einem angegebenen Schlüsselpfad in einem Dataset vorhanden ist. Wenn sich die angegebenen Daten ändern (oder im Verdacht einer Änderung stehen), werden die Datenconsumer benachrichtigt.

Datenconsumersammlung

Eine Datenverbrauchersammlung verfügt über die zusätzliche Möglichkeit, eine Liste ähnlicher Elemente zu verwalten. Diese Liste kann das gesamte Dataset sein, das von einer Datenquelle verwaltet wird, oder nur eine Teilmenge. In der Regel enthalten die Daten für jedes Element in der Liste ähnliche Arten von Informationen, aber dies ist keine Anforderung. Datenquellen und Datenconsumer können geschachtelte Listen unterstützen, z. B. eine Liste von Schlüsselwörtern, die jedem Foto in einer Liste von 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ächsten übergeordneten Liste oder zum Stamm des Datasets.

Beim Verarbeiten von Sammlungen wird jedem Datenconsumer im Prefab, das für jedes Sammlungselement instanziiert wird, der richtige aufgelöste Schlüsselpfad für den jeweiligen Eintrag in der Sammlung zugewiesen. Es wird verwendet, um den Schlüsselpfad für alle relativen (lokalen) Ansichtsdaten innerhalb dieses Prefabs vollständig aufzulösen.

Datensammlungselement-Placer

Ein Consumer von Sammlungsdaten benötigt ein Mittel, um Benutzeroberflächen mit Listen mit sich wiederholenden visuellen Elementen aufzufüllen, z. B. was in einer scrollbaren Liste von Produkten, Fotos oder Kontakten gefunden werden kann. Dies wird erreicht, indem dem Sammlungsdatenconsumer ein Item Placer zugewiesen wird. Dieser Elementplatzierungselement ist die Logik, die weiß, wie Listenelemente anzufordern, Prefabs mit Variablendaten aufgefüllt werden und diese dann dem Benutzer präsentieren, in der Regel durch Einfügen in eine Liste, die von einer UX-Layoutkomponente für Listen verwaltet wird.

Design

Bei der Themenerstellung werden alle Sanitäranlagen von Datenquellen und Datenconsumern verwendet. 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. Das Ergebnis 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-Designdatenfluss

MRTK Design

Design ist die Fähigkeit, die visuelle Ästhetik vieler UX-Elemente gleichzeitig zu verändern. In der Regel werden alle Daten, die zum Angeben eines Designs erforderlich sind, von einer einzelnen Datenquelle bereitgestellt, z. B. einem skriptfähigen Objekt. Es ist auch möglich, dass Daten nach Bedarf bereitgestellt oder basierend auf ihrem Zweck in logische Gruppen unterteilt werden.

MRTK3 Design

MRTK3-Design kombiniert mit Datenbindung

Datenbindung und Design können für ein einzelnes UX-Element gleichzeitig vorhanden sein. Jedes einzelne UX-Element kann gleichzeitig designiert und datengebunden sein. In diesem Szenario besteht der typische Flow darin, dass das datum, das aus einer Datenquelle stammt, verwendet wird, um den richtigen Designschlüsselpfad abzuleiten. Dieser Schlüsselpfad wird dann verwendet, um ein Objekt aus dem Design Datenquelle abzurufen, in der Regel ein ScriptableObject-Profil, aber potenziell jede Datenquelle, die einen Schlüsselpfad auflösen kann.

Um die Konfiguration von Design und Datenbindung zu vereinfachen, ist es möglich, Bindungsprofile zu erstellen, die von einem BindingConfigurator zur Instanziierungszeit verarbeitet werden.

  • Ein BindingConfigurator verarbeitet ein Bindungsprofil , um die Objekte in einem Prefab zu bestimmen, die designiert werden sollen, und ordnet keypaths sowohl gebundene Datenelemente als auch Themenelemente zu. Anschließend wird geeignete DataConsumers hinzugefügt, um diese visuellen Elemente an die richtigen Keypaths-Selektoren zu binden, die verwendet werden, um auf bestimmte Daten in einem oder DataSourcesmehreren zu verweisen, die in der Regel außerhalb des Prefabs selbst sind.
  • Designdaten werden von einem DataSource bereitgestellt, das Daten für jeden im Bindungsprofil identifizierten Schlüsselpfad enthält.
  • Ein ThemeProvider Hilfsskript erleichtert die Verwendung eines ScriptableObject als DataSource Design.
  • Das Standardmäßige UX-Design wird vom MRTK_UX_ThemeProfileScriptableObject bereitgestellt, das an ein DataSourceReflection in gebunden ThemeProviderist.

Flussdiagramm für Designprofildatenquellen

Eingebettete Datenquelle

Eine eingebettete Datenquelle ist in zwei Situationen geeignet:

  1. Wenn jede instance des Prefabs möglicherweise unterschiedliche Designeinstellungen aufweisen und eine eigene separate Datenquelle erfordert.
  2. Wenn alle Instanzen dieses Prefabs von einem gemeinsamen persistenten Designprofil (z. B. ScriptableObject) gesteuert werden und über die eingebettete Datenquelle bereitgestellt werden können, sodass keine externen Abhängigkeiten erstellt werden müssen.

DataSourceReflection

Dadurch kann jede C#-Struktur oder -Klasse in eine DataSource umgewandelt werden, indem mithilfe von Reflektion Schlüsselpfade zu Feldern, Eigenschaften, geschachtelten Klassen, Arrays, Listen oder Wörterbüchern zugeordnet werden. Es kann einem Unity ScriptableObject oder einer anderen C#-Struktur oder -Klasse zugeordnet werden, in der Designdaten vorhanden sind. Das instanziierte Objekt, das die Daten enthält, kann zur Laufzeit abhängigkeitsinjiziert und geändert werden.

  1. Skriptfähiges Objekt: nützlich für statische Designs, die von vielen Prefabs gemeinsam verwendet werden.
  2. Nichtpersistente C#-Struktur oder -Klasse: nützlich für dynamische Laufzeitänderungen des Designs.

DataSourceJson

Wenn die Daten als json Text vorhanden sind, werden sie durch Zuordnen von Schlüsselpfaden zum json DOM verwaltet. Binäre Ressourcen können aus den Ressourcen von Unity, StreamingAssets oder sogar einer abgerufenen URL abgerufen werden.

DataSourceDictionary

Dies ist eine einfache Option, wenn eine rein flache Liste gut genug ist, um den Bedarf zu erfüllen und schnelle Prototypen zu erstellen. Alle Designressourcen werden unterstützt, einschließlich Text, Unity-Ressourcen (z. B. Materialien, Sprites und Bilder), Ressourcen, StreamingAssets oder sogar extern über eine URL abrufbar.

Benutzerdefiniert

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

Design von UXComponents

Die im UXComponents-Paket bereitgestellten UXComponents-Standardsteuerelemente sind alle für die Unterstützung von Design konfiguriert. Sie ist standardmäßig DEAKTIVIERT, ist aber einfach zu aktivieren.

Jedes Steuerelement, in der Regel im obersten GameObject des Stamm-Prefabs, verfügt über ein Skript namens UXBindingConfigurator. Wenn dieses Skript aktiviert ist, werden die erforderlichen Datenbindungsskripts abgerufen, um das Design zu aktivieren. Achten Sie darauf, auch das Paket Datenbindung und Design zu importieren.

Hinweis zu TextMeshPro StyleSheets: Es ist derzeit nicht möglich, StyleSheets zum Formatieren der TextMeshPro Normal-Formatvorlage zu verwenden. Jede andere Formatvorlage, die im Standard-Stylesheet von TextMeshPro enthalten ist, kann verwendet werden. In den Beispielen wird Body verwendet, um diese Einschränkung zu umgehen.

DataSourceThemeProvider

MonoBehaviour DataSourceThemeProvider kann verwendet werden, um ein ScriptableObject, das alle Verweise auf alle Designobjekte enthält, ganz einfach als Datenquelle zu verwenden. Dies wird in der Szene UXThemingExample veranschaulicht.

ThemeSelector

Das ThemeSelector MonoBehaviour ermöglicht es, mehrere ScriptableObject-Profile anzugeben und einfach zwischen diesen auszutauschen. Ein Beispiel wäre, um den Wechsel zwischen einem "Dunkel"- und einem "Hell"-Design zu erleichtern. Fügen Sie scriptableObjects in der Theme ProfilesRegel zur Entwurfszeit hinzu. Ändern Sie dann zur Laufzeit die Current Theme -Eigenschaft, um das Design zu ändern.

Datenconsumerdesign

Das Design wird von Datenconsumer durchgeführt, insbesondere von den Klassen DataConsumerThemeBase<T>, DataConsumerTextStyle und benutzerdefinierten DataConsumer-Klassen, die jeder Entwickler implementieren kann, um die Designunterstützung zu verbessern.

Die DataConsumerThemeBase<T-Basisklasse> stellt Logik bereit, um einen ganzzahligen oder schlüsselbasierten Bezug aus einer primären Datenquelle zu verwenden, um den gewünschten Endwert aus einer sekundären Designdatenbank nachzuschlagen. Dies wird erreicht, indem die Eingabedaten einem Designschlüsselpfad zugeordnet werden und dann dieser Designschlüsselpfad verwendet wird, um den endgültigen Wert abzurufen. Dadurch kann jedes Element gleichzeitig datengebunden und designiert werden. Stellen Sie sich beispielsweise ein status Feld in einer Datenbank mit den Status Neu, Gestartet und Fertig vor, dargestellt durch die Werte 0, 1 und 2, wobei jedes durch ein Sprite-Symbol dargestellt wird. Für die Datenbindung wird ein Wert von 0 bis 2 verwendet, um den gewünschten Sprite nachzuschlagen. Bei Design und Datenbindung verweist das Designprofil auf die richtige Liste der drei Sprites im Designprofil, und dann wird der Wert von 0 bis 2 verwendet, um den richtigen Sprite aus dieser Liste auszuwählen. Dadurch kann sich die Formatierung dieser Symbole je nach Design unterscheiden.

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

Das Austauschen von Designs zur Laufzeit erfolgt durch Ersetzen der Daten in der Designdatenquelle durch ein neues Dataset, das in derselben Datenobjektmodelltopologie angeordnet 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 mit dem Namen MRTK_UXComponents_ThemeProfile. Das ThemeProvider.cs-Hilfsskript erleichtert die Verwendung dieses oder eines beliebigen ScriptableObject-Profils als Datenquelle.

Die Methode zum Anwenden eines Designs auf dynamische Daten kann in den meisten Fällen automatisch erkannt oder explizit angegeben werden.

Wenn das Datum verwendet wird, um das richtige Element aus der Designdatenquelle auszuwählen, ist der Prozess wie folgt:

  • 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 in 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 mithilfe der automatisch erkannten Methode abgerufen.

Datentypen

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

Datentyp Beschreibung
Automatische Erkennung Das Datum wird analysiert, und die richtige Interpretation wird automatisch erkannt. Weitere Informationen finden Sie unter "Datentyp automatisch erkennen".
DirectValue Es wird erwartet, dass das Datum vom gewünschten Typ T (z. B. Material, Sprite, Bild) ist und direkt verwendet wird.
DirectLookup Ein ganzzahliger Index oder Zeichenfolgenschlüssel, mit dem der gewünschte Wert aus einer lokalen Nachschlagetabelle gesucht wird.
StaticThemedValue Statisches Designobjekt des richtigen Typs wird aus der Designdatenquelle unter dem angegebenen Designschlüsselpfad abgerufen.
ThemeKeypathLookup Ein ganzzahliger Index oder Zeichenfolgenschlüssel wird verwendet, um den gewünschten Designschlüsselpfad nachzuschlagen.
ThemeKeypathProperty Ein Zeichenfolgeneigenschaftsname, der an den im Design bereitgestellten Basisschlüsselpfad angefügt wird.
ResourcePath Ein Ressourcenpfad zum Abrufen des Werts aus einer Unity-Ressource (kann mit "resource://" beginnen).
FilePath Ein Dateipfad zum Abrufen eines Unity-Streamingobjekts (kann mit "file://" beginnen).

Datentyp der automatischen Erkennung

Auto-Detect analysiert die empfangenen Daten und entscheidet automatisch über die Abrufmethode. In der Tabelle stellt T den gewünschten Typ dar, z. B. Material, Sprite, Bild. Die automatische Erkennung kann an zwei Stellen im Prozess auftreten:

  • Für den primären Datumswert selbst.
  • Für den designierten Wert, der über das primäre Datum abgerufen wird.
Datumstyp Überlegungen Hat Designhilfsprogramm Verhalten
T n/v J/N Direkt ohne Design verwendet
int alle ganzzahligen Grundtypen oder int32 parsable Zeichenfolgen Nein Wird als Index an abgeleitete GetObjectByIndex(n) übergeben, um ein N-ten Objekt vom Typ T abzurufen.
int alle ganzzahligen Grundtypen oder int32 parsable Zeichenfolgen Ja Index zum Abrufen des N-ten Designschlüsselpfads aus der lokalen Suche und anschließendes Abrufen des Designobjekts über die automatische Erkennung.
string Format: "resource://{resourcePath}" J/N resourcePath wird zum Abrufen der Unity-Ressource verwendet.
string Format: "file://{filePath} J/N filePath wird zum Abrufen eines Streamingobjekts verwendet.
string Andere Nein Wird als Schlüssel an abgeleitete GetObjectByKey() übergeben, um das übereinstimmende Objekt vom Typ T abzurufen.
string Andere Ja Schlüssel zum Abrufen des übereinstimmenden Designschlüsselpfads aus der lokalen Suche und anschließendes Abrufen des Designobjekts über die automatische Erkennung.

Beispiel für das Abrufen eines designierten status-Symbols aus einer Datenbank, die einen numerischen status Wert enthält:

  1. Der Schlüsselpfad für ein status-Symbol in der Datenbank ist status.sprite_index.
  2. Der abgerufene Wert für status.sprite_index ist 2, was "abgebrochen" status bedeutet.
  3. Der Eintrag N=2 (mit anderen Worten, dritter) in der DataConsumerSprite-Suche ist auf "Status.Icons.Cancelled" festgelegt.
  4. Der Schlüsselpfad, der zum Abrufen eines Werts aus der Datenquelle "Design" verwendet wird.
  5. Der Wert für den Schlüsselpfad "Status.Icons.Cancelled" ist "resource://Sprites/sprite_cancelled".
  6. Die automatische Erkennung bestimmt, dass das Symbol über eine Ressource unter "Ressourcen/Sprites/sprite_cancelled" abgerufen werden soll.

TextMeshPro StyleSheets

Mit Dem Design können TMPro-Stylesheets aktiviert werden. "TMP-Einstellungen" ScriptableObject gibt vor, wo Stylesheets in den Ressourcen erwartet werden. Dies ist die Eigenschaft "Default Font Asset => Path".

Stellen Sie sicher, dass Sie alle App-spezifischen StyleSheets in demselben Unterpfad außerhalb von Ressourcen platzieren. Wenn Sie sie anders organisieren möchten, stellen Sie sicher, dass Sie "TMP-Einstellungen" entsprechend aktualisieren.

Gestalten neuer UX-Steuerelemente

Wenn Sie neue UX-Steuerelemente entwickeln, ist es relativ einfach, diese zu gestalten. 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 zu erben MRTK_UXCore_ThemeProfile und weitere Themenfelder hinzuzufügen oder Ihre Steuerelemente auf Ihr eigenes ScriptableObject zu verweisen. Es gibt nichts Magisches an den bereitgestellten; Die organization des ScriptableObject bestimmen die Schlüsselpfade, die für den Zugriff auf einzelne Datenelemente über C#-Reflektion erforderlich sind.

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 KeyPath-Zuordnungen bereitgestellt, die erforderlich sind, um Ihre designfähigen Elemente den im Designprofil bereitgestellten Daten zuzuordnen. Dieses Skript fügt zur Laufzeit automatisch alle erforderlichen DataConsumerXXX-Komponenten hinzu, um das design zu unterstützen, das Sie verwenden möchten.

Erste Schritte

Anforderungen

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

Beispielszenen

Sehen Sie sich zunächst die verschiedenen Datenbindungsbeispielszenen im MRTK-Beispielpaket genau an, und sehen Sie sich an, wie die verschiedenen MonoBehaviours-Datenquellen konfiguriert werden. Im Allgemeinen müssen Datenbindungsskripts nur auf der höchsten Ebene gameObject eines Prefabs oder einer zugehörigen Gruppe von UX-Elementen platziert werden.

In den meisten Anwendungsfällen funktionieren die Standardwerte standardmäßig, aber die verfügbar gemachten Eigenschaften bieten Flexibilität für die komplexeren Fälle.

Hinweis

Um das Design für die standardmäßigen MRTK-UX-Komponenten zu aktivieren, muss das Symbol in den MRTK_UX_DATABINDING_THEMING_ENABLED Playereinstellungen definiert werden. Dieses Symbol stellt sicher, dass sich keine Auswirkungen auf die Leistung auswirken, wenn kein Design erforderlich ist.

Assets/DataBinding Example/Scenes/DataBindingExamples.scene

In dieser Szene werden verschiedene Szenarien mit variablen Daten veranschaulicht. Laden Sie die Szene, und spielen Sie es wieder. Beachten Sie folgendes:

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

  • Spielobjekte für Sprites und Text verfügen über eine Form der Datenverbraucherkomponente, die den Empfang von Daten und das Aktualisieren von Ansichten verwaltet.

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

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

  • Ein übergeordnetes Spielobjekt verfügt über eine Datenquellenkomponente, die Daten für alle untergeordneten Spielobjekte bereitstellt, die einen zugehörigen Satz variabler Informationen darstellen.

  • Eine Sammlung Data Consumer gibt ein Prefab an, das selbst Datenconsumer enthält, die verwendet werden, um dieses Prefab mit Variablendaten aufzufüllen.

Assets/UX-Designbeispiel/Szenen/AudioTheming

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

Assets/UX-Designbeispiel/Szenen/BatteryLevelExample

In diesem Beispiel werden Design und Datenbindung kombiniert, um einen Akkustand sowohl als numerischen Wert als auch als Symbol anzuzeigen. Design wird verwendet, um zwischen einem "Laden" und einem "Nicht laden"-Design auszuwählen. Es ist so konzipiert, dass die folgenden Ziele erfüllt werden:

  • Alle visuellen Ressourcen können in einem einzelnen ScriptableObject vorhanden sein, das als Designprofil fungiert.
  • Die Anzahl der Sprites für "Ladezustände" kann von der Anzahl für den Zustand "nicht geladen" abweichen.
  • Der Algorithmus zum Zuordnen des gemeldeten Akkustands zu einem bestimmten Sprite kann nicht linear sein und sich zwischen den Zuständen "Laden" und "Nicht laden" unterscheiden.
  • Alle visuellen Ressourcen können in einem einzelnen ScriptableObject vorhanden sein, das als Designprofil fungiert.
  • Die Anzahl der Sprites für Ladezustände kann von der Anzahl für nicht geladenen Zustand abweichen.
  • Der Algorithmus zum Zuordnen des gemeldeten Akkustands, zu dem Sprite nichtlinear sein kann und sich zwischen lade- und nicht ladezustand unterscheidet.

Hinweis

Die Struktur dieser Demo ist kein gutes Beispiel für die Kombination von Design und Datenbindung. In einer Produktionsanwendung zur ordnungsgemäßen Trennung von Modell und Ansicht würde der tatsächliche Akkuzustand (Füllstand und Laden) in einer separaten Datenquelle als die Ressourcenlocatoren für die Sprites selbst bereitgestellt.

Assets/UX-Designbeispiel/Szenen/UXThemingExample

In diesem Beispiel wird das Ändern des Designs einer gesamten Anwendung sowie die Verwendung DataSourceGODictionary von als Datenquelle zum Verwalten einer Vielzahl von Textinhalten veranschaulicht, die in der Benutzeroberfläche angezeigt werden sollen. In einem umfassenderen Szenario bieten die anderen flexibleren Datenquellentypen wahrscheinlich die erforderliche Flexibilität, z DataSourceReflection . B. oder DataSourceGOJson.

Erstes Datenbindungsprojekt

Hier ist ein einfaches Beispiel, das Ihnen den schnellen Einstieg erleichtert:

  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 in "Datenbindung" um. Fügen Sie eine DataSourceJsonTest-Komponente hinzu.
  4. Ändern Sie im Inspektor die URL in eine Website, die eine Datensuche bereitstellt.
  5. Fügen Sie dem Datenbindungsspielobjekt ein Objekt der Benutzeroberfläche> Text - TextMeshPro hinzu. Es fügt eine Canvas und dann ein "Text (TMP)"-Objekt hinzu.
  6. Wählen Sie das Text -Objekt (TMP) aus, und ändern Sie im Inspector die Texteingabe in:

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

  1. Wählen Sie das Canvas-Objekt aus, und fügen Sie eine Textkomponente des Datenconsumers 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 Datenconsumer bereit. Es kann sich um beliebige Daten handeln: algorithmisch generiert, im RAM, auf einem Datenträger oder aus einer zentralen Datenbank abgerufen.

Alle Datenquellen müssen die IDataSource-Schnittstelle bereitstellen. Einige der grundlegenden Funktionen werden in einer Basisklasse namens DataSourceBaseangeboten. Wahrscheinlich möchten Sie von dieser Klasse ableiten, um die spezifische Datenverwaltungsfunktionalität hinzuzufügen, die speziell für Ihre Anforderungen geeignet ist.

Damit eine Datenquelle als Komponente in einem Spielobjekt abgelegt werden kann, gibt es ein weiteres Basisobjekt namens DataSourceGOBase , wobei GO für GameObject steht. Dies ist ein MonoBehavior, der als Komponente auf ein GameObject abgelegt werden kann. Es handelt sich um einen schlanken Proxy, der zum Delegieren von Arbeit an eine nicht Unity-spezifische Kerndatenquelle entwickelt wurde.

Eine Datenquelle kann die Möglichkeit zum Bearbeiten von Daten im Unity-Editor verfügbar machen. Wenn ja, kann die abgeleitete Klasse die Datenquellenlogik enthalten, oder sie kann eine "bestandsbasierte" Datenquelle verwenden, aber auch Inspektorfelder oder andere Möglichkeiten zum Konfigurieren der Daten hinzufügen.

Schreiben eines neuen Datenconsumers

Ein Datenconsumer erhält Benachrichtigungen, wenn sich Daten ändern, und aktualisiert dann einen Aspekt der Benutzeroberfläche, z. B. den Text, der in einer TextMeshPro-Komponente angezeigt wird.

Alle Datenconsumer müssen die IDataConsumer-Schnittstelle bereitstellen. Einige der grundlegenden Funktionen werden in einer Basisklasse namens DataConsumerGOBaseangeboten, wobei GO für GameObject steht.

Die meiste Arbeit eines Datenconsumers besteht darin, neue Daten zu akzeptieren und sie dann für die Präsentation vorzubereiten. Dies kann so einfach wie die Auswahl des richtigen Prefabs sein oder das Abrufen weiterer Daten aus einem Clouddienst wie einem Content Management-System bedeuten.

Schreiben eines Datensammlungselement-Placers

Ein Datensammlungselement-Placer ist dafür verantwortlich, zu verwalten, welche Teile einer Sammlung derzeit sichtbar sind und wie diese sichtbare Sammlung dargestellt wird, unabhängig davon, ob es sich bei der Sammlung um eine kleine statische Liste oder eine riesige Millionen Datensatzdatenbank handelt.

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

Bekannte Einschränkungen und fehlende Features

  • 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 aufgrund eines HTTPS-SSL-Fehlers in späteren Versionen von Unity nicht auf HoloLens.
  • Zusätzliche Leistungsoptimierung.
  • Diese Version konzentriert sich auf die Datendarstellung, nicht auf die Datenerfassung. MRTK-UX-Steuerelemente sind noch nicht verkabelt, um den Zustand in einem DataSourcefestzulegen.
  • Dynamische Änderungen an Listendaten aktualisieren die gesamte Liste vollständig, anstatt inkrementell zu aktualisieren.
  • Datenbearbeitungspipeline nicht implementiert
  • Das Auffüllen aller UX-Komponenten auf einem Slate wird noch nicht vollständig unterstützt.
  • DataSourceJson-Knoten sollten eine Schnittstelle implementieren IDataNode , die mit DataSourceObjects interoperabel ist.