Plattformübergreifende App-Fallstudie: Tasky
Tasky Portable ist eine einfache Aufgabenlistenanwendung. In diesem Dokument wird erläutert, wie es entworfen und erstellt wurde, und zwar im Anschluss an die Anleitung des Dokuments "Plattformübergreifende Anwendungen erstellen" . Die Diskussion behandelt die folgenden Bereiche:
Entwurfsprozess
Es ist ratsam, eine Straßenkarte für das zu erstellen, was Sie erreichen möchten, bevor Sie mit dem Codieren beginnen. Dies gilt insbesondere für plattformübergreifende Entwicklung, bei der Sie Funktionen erstellen, die auf mehrere Arten verfügbar gemacht werden. Beginnend mit einer klaren Vorstellung davon, was Sie erstellen, spart Später im Entwicklungszyklus Zeit und Aufwand.
Anforderungen
Der erste Schritt beim Entwerfen einer Anwendung besteht darin, die gewünschten Features zu identifizieren. Hierbei kann es sich um allgemeine Ziele oder detaillierte Anwendungsfälle handelt. Tasky hat einfache funktionale Anforderungen:
- Anzeigen einer Liste von Aufgaben
- Hinzufügen, Bearbeiten und Löschen von Aufgaben
- Festlegen des Status eines Vorgangs auf "Fertig"
Sie sollten die Verwendung plattformspezifischer Features in Betracht ziehen. Können Tasky iOS-Geofencing- oder Windows Phone Live-Kacheln nutzen? Auch wenn Sie in der ersten Version keine plattformspezifischen Features verwenden, sollten Sie vorausplanen, um sicherzustellen, dass Ihre Geschäfts- und Datenebenen diese berücksichtigen können.
Benutzeroberflächendesign
Beginnen Sie mit einem allgemeinen Design, das auf den Zielplattformen implementiert werden kann. Achten Sie darauf, plattformspezifische UI-Einschränkungen zu beachten. Beispielsweise kann ein TabBarController
iOS mehr als fünf Schaltflächen anzeigen, während das Windows Phone-Äquivalent bis zu vier anzeigen kann.
Zeichnen Sie den Bildschirmfluss mithilfe des Tools Ihrer Wahl (Papierarbeiten).
Datenmodell
Wenn Sie wissen, welche Daten gespeichert werden müssen, können Sie bestimmen, welcher Persistenzmechanismus verwendet werden soll. Unter Plattformübergreifender Datenzugriff finden Sie Informationen zu den verfügbaren Speichermechanismen und helfen bei der Entscheidung zwischen ihnen. Für dieses Projekt verwenden wir SQLite.NET.
Tasky muss drei Eigenschaften für jedes "TaskItem"-Objekt speichern:
- Name – Zeichenfolge
- Notizen – Zeichenfolge
- Fertig – Boolescher Wert
Kernfunktionalität
Berücksichtigen Sie die API, die die Benutzeroberfläche nutzen muss, um die Anforderungen zu erfüllen. Für eine Aufgabenliste sind die folgenden Funktionen erforderlich:
- Alle Aufgaben auflisten – um die Hauptbildschirmliste aller verfügbaren Aufgaben anzuzeigen
- Abrufen einer Aufgabe – wenn eine Aufgabenzeile berührt wird
- Speichern einer Aufgabe – wenn eine Aufgabe bearbeitet wird
- Löschen einer Aufgabe – wenn eine Aufgabe gelöscht wird
- Erstellen einer leeren Aufgabe – wenn eine neue Aufgabe erstellt wird
Um die Codewiederverwendung zu erreichen, sollte diese API einmal in der portablen Klassenbibliothek implementiert werden.
Implementierung
Nachdem das Anwendungsdesign vereinbart wurde, überlegen Sie, wie sie als plattformübergreifende Anwendung implementiert werden kann. Dies wird zur Architektur der Anwendung. Im Anschluss an die Anleitung im Dokument "Plattformübergreifende Anwendungen erstellen" sollte der Anwendungscode in die folgenden Teile unterteilt werden:
- Common Code – ein gängiges Projekt, das wiederverwendbaren Code zum Speichern der Vorgangsdaten enthält; eine Model-Klasse und eine API zum Verwalten des Speicherns und Ladens von Daten verfügbar machen.
- Plattformspezifischer Code – plattformspezifische Projekte, die eine systemeigene Benutzeroberfläche für jedes Betriebssystem implementieren, wobei der gemeinsame Code als "Back-End" verwendet wird.
Diese beiden Teile werden in den folgenden Abschnitten beschrieben.
Allgemeiner Code (PCL)
Tasky Portable verwendet die Portable Class Library-Strategie zum Freigeben von gemeinsamem Code. Eine Beschreibung der Codefreigabeoptionen finden Sie im Dokument "Freigabecodeoptionen ".
Der gesamte gemeinsame Code, einschließlich datenzugriffsebene, Datenbankcode und Verträge, wird im Bibliotheksprojekt platziert.
Das vollständige PCL-Projekt ist unten dargestellt. Der gesamte Code in der portablen Bibliothek ist mit jeder zielbezogenen Plattform kompatibel. Bei der Bereitstellung referenziert jede systemeigene App auf diese Bibliothek.
Das folgende Klassendiagramm zeigt die Klassen nach Ebene gruppiert. Die SQLiteConnection
Klasse ist Codebausteine aus dem Sqlite-NET-Paket. Die restlichen Klassen sind benutzerdefinierter Code für Tasky. Die TaskItemManager
klassen TaskItem
stellen die API dar, die für die plattformspezifischen Anwendungen verfügbar gemacht wird.
Die Verwendung von Namespaces zum Trennen der Ebenen hilft beim Verwalten von Verweisen zwischen den einzelnen Ebenen. Die plattformspezifischen Projekte sollten nur eine using
Anweisung für die Business Layer enthalten. Die Datenzugriffsschicht und die Datenebene sollten von der API gekapselt werden, die von TaskItemManager
der Geschäftsebene verfügbar gemacht wird.
References
Portable Klassenbibliotheken müssen auf mehreren Plattformen verwendet werden können, wobei jeweils unterschiedliche Unterstützungsebenen für Plattform- und Frameworkfeatures gelten. Aus diesem Hintergrund gibt es Einschränkungen dafür, welche Pakete und Frameworkbibliotheken verwendet werden können. Beispielsweise unterstützt Xamarin.iOS das c# dynamic
-Schlüsselwort nicht, sodass eine portable Klassenbibliothek kein Paket verwenden kann, das von dynamischem Code abhängt, obwohl dieser Code unter Android funktioniert. Visual Studio für Mac verhindern, dass Sie inkompatible Pakete und Verweise hinzufügen, aber Sie sollten Einschränkungen beachten, um Überraschungen später zu vermeiden.
Hinweis: Ihre Projekte verweisen auf Frameworkbibliotheken, die Sie nicht verwendet haben. Diese Verweise werden als Teil der Xamarin-Projektvorlagen eingeschlossen. Wenn Apps kompiliert werden, entfernt der Verknüpfungsprozess nicht referenzierten Code. System.Xml
Obwohl darauf verwiesen wurde, wird er nicht in die endgültige Anwendung einbezogen, da wir keine XML-Funktionen verwenden.
Data Layer (DL)
Die Datenschicht enthält den Code, mit dem die physische Speicherung von Daten ausgeführt wird – unabhängig davon, ob es sich um eine Datenbank, flat files oder einen anderen Mechanismus handelt. Die Tasky-Datenschicht besteht aus zwei Teilen: der SQLite-NET-Bibliothek und dem benutzerdefinierten Code, der zum Verknüpfen hinzugefügt wurde.
Tasky basiert auf dem Sqlite-net NuGet-Paket (veröffentlicht von Frank Krueger), um SQLite-NET-Code einzubetten, der eine Object-Relational Mapping (ORM)-Datenbankschnittstelle bereitstellt. Die TaskItemDatabase
Klasse erbt von SQLiteConnection
und fügt die erforderlichen Create-, Read-, Update-, Delete -, Delete (CRUD)-Methoden zum Lesen und Schreiben von Daten in SQLite hinzu. Es handelt sich um eine einfache Textbausteineimplementierung generischer CRUD-Methoden, die in anderen Projekten wiederverwendet werden können.
Dies TaskItemDatabase
ist ein Singleton, der sicherstellt, dass der gesamte Zugriff für dieselbe Instanz erfolgt. Eine Sperre wird verwendet, um den gleichzeitigen Zugriff von mehreren Threads zu verhindern.
SQLite unter Windows Phone
Während iOS und Android beide als Teil des Betriebssystems mit SQLite ausgeliefert werden, enthält Windows Phone kein kompatibles Datenbankmodul. Um Code auf allen drei Plattformen freizugeben, ist eine systemeigene Windows-Version von SQLite erforderlich. Weitere Informationen zum Einrichten Ihres Windows Phone-Projekts für Sqlite finden Sie unter Arbeiten mit einer lokalen Datenbank .
Verwenden einer Schnittstelle zum Generalisieren des Datenzugriffs
Die Datenschicht benötigt eine Abhängigkeit BL.Contracts.IBusinessIdentity
, sodass sie abstrakte Datenzugriffsmethoden implementieren kann, die einen Primärschlüssel erfordern. Jede Business Layer-Klasse, die die Schnittstelle implementiert, kann dann in der Datenebene beibehalten werden.
Die Schnittstelle gibt lediglich eine ganzzahlige Eigenschaft an, die als Primärschlüssel fungiert:
public interface IBusinessEntity {
int ID { get; set; }
}
Die Basisklasse implementiert die Schnittstelle und fügt die SQLite-NET-Attribute hinzu, um sie als automatisch inkrementierenden Primärschlüssel zu markieren. Jede Klasse in der Business Layer, die diese Basisklasse implementiert, kann dann in der Datenebene beibehalten werden:
public abstract class BusinessEntityBase : IBusinessEntity {
public BusinessEntityBase () {}
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
}
Ein Beispiel für die generischen Methoden in der Datenschicht, die die Schnittstelle verwenden, ist diese GetItem<T>
Methode:
public T GetItem<T> (int id) where T : BL.Contracts.IBusinessEntity, new ()
{
lock (locker) {
return Table<T>().FirstOrDefault(x => x.ID == id);
}
}
Sperren, um gleichzeitigen Zugriff zu verhindern
Eine Sperre wird innerhalb der TaskItemDatabase
Klasse implementiert, um gleichzeitigen Zugriff auf die Datenbank zu verhindern. Dadurch wird sichergestellt, dass gleichzeitiger Zugriff aus verschiedenen Threads serialisiert wird (andernfalls kann eine UI-Komponente versuchen, die Datenbank gleichzeitig zu lesen, wenn ein Hintergrundthread aktualisiert wird). Hier sehen Sie ein Beispiel für die Implementierung der Sperre:
static object locker = new object ();
public IEnumerable<T> GetItems<T> () where T : BL.Contracts.IBusinessEntity, new ()
{
lock (locker) {
return (from i in Table<T> () select i).ToList ();
}
}
public T GetItem<T> (int id) where T : BL.Contracts.IBusinessEntity, new ()
{
lock (locker) {
return Table<T>().FirstOrDefault(x => x.ID == id);
}
}
Der Großteil des Data Layer-Codes kann in anderen Projekten wiederverwendet werden. Der einzige anwendungsspezifische Code auf der Ebene ist der CreateTable<TaskItem>
Aufruf im TaskItemDatabase
Konstruktor.
Datenzugriffsebene (DAL)
Die TaskItemRepository
Klasse kapselt den Datenspeichermechanismus mit einer stark typierten API, mit der Objekte erstellt, gelöscht, abgerufen und aktualisiert werden können TaskItem
.
Verwenden der bedingten Kompilierung
Die Klasse verwendet die bedingte Kompilierung, um den Dateispeicherort festzulegen . Dies ist ein Beispiel für die Implementierung von Platform Divergence. Die Eigenschaft, die den Pfad zurückgibt, kompiliert in verschiedenen Code auf jeder Plattform. Die code- und plattformspezifischen Compilerdirektiven werden hier gezeigt:
public static string DatabaseFilePath {
get {
var sqliteFilename = "TaskDB.db3";
#if SILVERLIGHT
// Windows Phone expects a local path, not absolute
var path = sqliteFilename;
#else
#if __ANDROID__
// Just use whatever directory SpecialFolder.Personal returns
string libraryPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); ;
#else
// we need to put in /Library/ on iOS5.1+ to meet Apple's iCloud terms
// (they don't want non-user-generated data in Documents)
string documentsPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal); // Documents folder
string libraryPath = Path.Combine (documentsPath, "..", "Library"); // Library folder
#endif
var path = Path.Combine (libraryPath, sqliteFilename);
#endif
return path;
}
}
Je nach Plattform lautet die Ausgabe "<App-Pfad>/Library/TaskDB.db3" für iOS, "<App-Pfad>/Dokumente/TaskDB.db3" für Android oder nur "TaskDB.db3" für Windows Phone.
Business Layer (BL)
Die Business Layer implementiert die Modellklassen und eine Fassade, um sie zu verwalten.
In Tasky ist das Modell die TaskItem
Klasse und TaskItemManager
implementiert das Fassadenmuster, um eine API für die Verwaltung TaskItems
bereitzustellen.
Fassade
TaskItemManager
umschließt die DAL.TaskItemRepository
Methode "Get", "Save" und "Delete", auf die von den Anwendungs- und UI-Ebenen verwiesen wird.
Geschäftsregeln und Logik würden hier platziert, wenn erforderlich – z. B. alle Überprüfungsregeln, die erfüllt sein müssen, bevor ein Objekt gespeichert wird.
API für plattformspezifischen Code
Nachdem der gemeinsame Code geschrieben wurde, muss die Benutzeroberfläche erstellt werden, um die darin verfügbar gemachten Daten zu sammeln und anzuzeigen. Die TaskItemManager
Klasse implementiert das Fassadenmuster, um eine einfache API für den Anwendungscode für den Zugriff bereitzustellen.
Der in jedem plattformspezifischen Projekt geschriebene Code wird in der Regel eng mit dem systemeigenen SDK dieses Geräts gekoppelt und nur auf den gemeinsamen Code mithilfe der durch die TaskItemManager
API definierten API zugreifen. Dazu gehören die Methoden und Geschäftsklassen, die sie verfügbar machen, z TaskItem
. B. .
Bilder werden nicht plattformübergreifend freigegeben, sondern unabhängig zu jedem Projekt hinzugefügt. Dies ist wichtig, da jede Plattform Bilder unterschiedlich verarbeitet, wobei verschiedene Dateinamen, Verzeichnisse und Auflösungen verwendet werden.
In den verbleibenden Abschnitten werden die plattformspezifischen Implementierungsdetails der Tasky-Benutzeroberfläche erläutert.
iOS-App
Es sind nur eine Handvoll Klassen erforderlich, um die iOS Tasky-Anwendung mithilfe des allgemeinen PCL-Projekts zum Speichern und Abrufen von Daten zu implementieren. Das vollständige iOS Xamarin.iOS-Projekt wird unten gezeigt:
Die Klassen werden in diesem Diagramm dargestellt, gruppiert in Ebenen.
References
Die iOS-App verweist auf die plattformspezifischen SDK-Bibliotheken – z. B. Xamarin.iOS und MonoTouch.Dialog-1.
Außerdem muss auf das TaskyPortableLibrary
PCL-Projekt verwiesen werden.
Die Liste der Verweise wird hier gezeigt:
Die Application Layer- und User Interface Layer werden in diesem Projekt mithilfe dieser Verweise implementiert.
Application Layer (AL)
Die Anwendungsschicht enthält plattformspezifische Klassen, die zum "Binden" der objekte erforderlich sind, die von der PCL an die Benutzeroberfläche verfügbar gemacht werden. Die iOS-spezifische Anwendung verfügt über zwei Klassen zum Anzeigen von Aufgaben:
- EditingSource – Diese Klasse wird verwendet, um Aufgabenlisten an die Benutzeroberfläche zu binden. Da
MonoTouch.Dialog
für die Aufgabenliste verwendet wurde, müssen wir diese Hilfsfunktion implementieren, um Wisch-zu-Löschen-Funktionen in derUITableView
. Wisch-zu-Löschen ist in iOS üblich, aber nicht unter Android oder Windows Phone, sodass das iOS-spezifische Projekt der einzige ist, der es implementiert. - TaskDialog – Diese Klasse wird verwendet, um eine einzelne Aufgabe an die Benutzeroberfläche zu binden. Es verwendet die
MonoTouch.Dialog
Spiegelungs-API, um dasTaskItem
Objekt mit einer Klasse zu "umbrechen", die die richtigen Attribute enthält, damit der Eingabebildschirm ordnungsgemäß formatiert werden kann.
Die TaskDialog
Klasse verwendet MonoTouch.Dialog
Attribute, um einen Bildschirm basierend auf den Eigenschaften einer Klasse zu erstellen. Die Klasse sieht wie folgt aus:
public class TaskDialog {
public TaskDialog (TaskItem task)
{
Name = task.Name;
Notes = task.Notes;
Done = task.Done;
}
[Entry("task name")]
public string Name { get; set; }
[Entry("other task info")]
public string Notes { get; set; }
[Entry("Done")]
public bool Done { get; set; }
[Section ("")]
[OnTap ("SaveTask")] // method in HomeScreen
[Alignment (UITextAlignment.Center)]
public string Save;
[Section ("")]
[OnTap ("DeleteTask")] // method in HomeScreen
[Alignment (UITextAlignment.Center)]
public string Delete;
}
Beachten Sie, dass für die OnTap
Attribute ein Methodenname erforderlich ist – diese Methoden müssen in der Klasse vorhanden sein, in der die MonoTouch.Dialog.BindingContext
Klasse erstellt wird (in diesem Fall die HomeScreen
im nächsten Abschnitt erläuterte Klasse).
Benutzeroberflächenebene (UI)
Die Benutzeroberfläche besteht aus den folgenden Klassen:
- AppDelegate – Enthält Aufrufe der Darstellungs-API zum Formatieren der Schriftarten und Farben, die in der Anwendung verwendet werden. Tasky ist eine einfache Anwendung, sodass keine anderen Initialisierungsaufgaben ausgeführt werden
FinishedLaunching
. - Bildschirme – Unterklassen, die
UIViewController
jeden Bildschirm und sein Verhalten definieren. Bildschirme verbinden die Benutzeroberfläche mit Application Layer-Klassen und der allgemeinen API (TaskItemManager
). In diesem Beispiel werden die Bildschirme im Code erstellt, aber sie könnten mit dem Schnittstellen-Generator von Xcode oder dem Storyboard-Designer entworfen worden sein. - Bilder – Visuelle Elemente sind ein wichtiger Bestandteil jeder Anwendung. Tasky verfügt über Begrüßungsbildschirm- und Symbolbilder, die für iOS in normaler und Netzhautauflösung bereitgestellt werden müssen.
Startbildschirm
Der Startbildschirm ist ein MonoTouch.Dialog
Bildschirm, der eine Liste der Aufgaben aus der SQLite-Datenbank anzeigt. Er erbt von DialogViewController
code und implementiert ihn, um festzulegen, dass es eine Auflistung von TaskItem
Objekten für die Root
Anzeige enthält.
Die beiden wichtigsten Methoden im Zusammenhang mit der Anzeige und Interaktion mit der Aufgabenliste sind:
- PopulateTable – Verwendet die Business Layer-Methode
TaskManager.GetTasks
, um eine Sammlung vonTaskItem
Objekten abzurufen, die angezeigt werden sollen. - Ausgewählt – Wenn eine Zeile berührt wird, wird die Aufgabe auf einem neuen Bildschirm angezeigt.
Bildschirm "Vorgangsdetails"
Vorgangsdetails ist ein Eingabebildschirm, über den Aufgaben bearbeitet oder gelöscht werden können.
Tasky verwendet MonoTouch.Dialog
die Spiegelungs-API, um den Bildschirm anzuzeigen, sodass keine UIViewController
Implementierung vorhanden ist. Stattdessen instanziiert die HomeScreen
Klasse und zeigt eine DialogViewController
Using-Klasse TaskDialog
aus der Application Layer an.
Dieser Screenshot zeigt einen leeren Bildschirm, der das Entry
Attribut zum Festlegen des Wasserzeichentexts in den Feldern "Name " und "Notizen " veranschaulicht:
Die Funktionalität des Bildschirms "Vorgangsdetails " (z. B. Speichern oder Löschen einer Aufgabe) muss in der Klasse implementiert werden, da dies der Ort ist, an dem HomeScreen
die MonoTouch.Dialog.BindingContext
Aufgabe erstellt wird. Die folgenden HomeScreen
Methoden unterstützen den Bildschirm "Vorgangsdetails":
- ShowTaskDetails – Erstellt einen
MonoTouch.Dialog.BindingContext
Zum Rendern eines Bildschirms. Er erstellt den Eingabebildschirm mithilfe der Spiegelung, um Eigenschaftsnamen und -typen aus derTaskDialog
Klasse abzurufen. Zusätzliche Informationen, z. B. der Wasserzeichentext für die Eingabefelder, werden mit Attributen für die Eigenschaften implementiert. - SaveTask – Auf diese Methode wird über ein
OnTap
Attribut in derTaskDialog
Klasse verwiesen. Sie wird aufgerufen, wenn "Speichern " gedrückt wird, und verwendet einenMonoTouch.Dialog.BindingContext
, um die vom Benutzer eingegebenen Daten abzurufen, bevor die Änderungen mithilfeTaskItemManager
gespeichert werden. - DeleteTask – Auf diese Methode wird über ein
OnTap
Attribut in derTaskDialog
Klasse verwiesen. Die Daten werdenTaskItemManager
mithilfe des Primärschlüssels (ID-Eigenschaft) gelöscht.
Android-App
Das vollständige Xamarin.Android-Projekt ist unten dargestellt:
Das Klassendiagramm mit nach Ebene gruppierten Klassen:
References
Das Android-App-Projekt muss auf die plattformspezifische Xamarin.Android-Assembly verweisen, um auf Klassen aus dem Android SDK zuzugreifen.
Sie muss auch auf das PCL-Projekt verweisen (z. B. TaskyPortableLibrary) für den Zugriff auf den allgemeinen Daten- und Geschäftsschichtcode.
Application Layer (AL)
Ähnlich wie bei der iOS-Version, die wir zuvor betrachtet haben, enthält die Anwendungsschicht in der Android-Version plattformspezifische Klassen, die zum Binden der Objekte erforderlich sind, die von der Core-Schnittstelle an die Benutzeroberfläche verfügbar gemacht werden.
TaskListAdapter – zum Anzeigen einer Liste<T> von Objekten müssen wir einen Adapter implementieren, um benutzerdefinierte Objekte in einem ListView
. Der Adapter steuert, welches Layout für jedes Element in der Liste verwendet wird – in diesem Fall verwendet der Code ein integriertes Android-Layout SimpleListItemChecked
.
Benutzeroberfläche (UI)
Die Benutzeroberfläche der Android-App ist eine Kombination aus Code und XML-Markup.
- Ressourcen/Layout – Bildschirmlayouts und das Zeilenzellendesign als AXML-Dateien implementiert. Die AXML kann von Hand geschrieben oder visuell mithilfe des Xamarin UI-Designers für Android gestaltet werden.
- Ressourcen/Drawable – Bilder (Symbole) und benutzerdefinierte Schaltfläche.
- Bildschirme – Aktivitätsunterklassen, die jeden Bildschirm und sein Verhalten definieren. Verknüpft die Benutzeroberfläche mit Application Layer-Klassen und der allgemeinen API (
TaskItemManager
).
Startbildschirm
Der Startbildschirm besteht aus einer Aktivitätsunterklasse HomeScreen
und der HomeScreen.axml
Datei, die das Layout definiert (Position der Schaltfläche und Aufgabenliste). Der Bildschirm sieht wie folgt aus:
Der Code für den Startbildschirm definiert die Handler für das Klicken auf die Schaltfläche und das Klicken auf Elemente in der Liste sowie das Auffüllen der Liste in der OnResume
Methode (sodass änderungen, die im Bildschirm "Aufgabendetails" vorgenommen wurden) angezeigt werden. Daten werden mit den Geschäftsebenen TaskItemManager
und der TaskListAdapter
aus der Anwendungsschicht geladen.
Bildschirm "Vorgangsdetails"
Der Bildschirm "Vorgangsdetails" besteht auch aus einer Activity
Unterklasse und einer AXML-Layoutdatei. Das Layout bestimmt die Position der Eingabesteuerelemente, und die C#-Klasse definiert das Verhalten zum Laden und Speichern TaskItem
von Objekten.
Alle Verweise auf die PCL-Bibliothek werden über die TaskItemManager
Klasse ausgeführt.
Windows Phone-App
Das vollständige Windows Phone-Projekt:
Das folgende Diagramm zeigt die Klassen, die in Ebenen gruppiert sind:
References
Das plattformspezifische Projekt muss auf die erforderlichen plattformspezifischen Bibliotheken (z Microsoft.Phone
. B. und System.Windows
) verweisen, um eine gültige Windows Phone-Anwendung zu erstellen.
Außerdem muss auf das PCL-Projekt (z. B. TaskyPortableLibrary
) verwiesen werden, um die TaskItem
Klasse und Datenbank zu verwenden.
Application Layer (AL)
Wie bei den iOS- und Android-Versionen besteht die Anwendungsebene aus den nicht visuellen Elementen, die dazu beitragen, Daten an die Benutzeroberfläche zu binden.
ViewModels
ViewModels umschließen Daten aus der PCL ( TaskItemManager
) und stellt sie so dar, dass sie von silverlight-/XAML-Datenbindung genutzt werden kann. Dies ist ein Beispiel für plattformspezifisches Verhalten (wie im Dokument für plattformübergreifende Anwendungen erläutert).
Benutzeroberfläche (UI)
XAML verfügt über eine eindeutige Datenbindungsfunktion, die im Markup deklariert werden kann und die Zum Anzeigen von Objekten erforderliche Codemenge verringern kann:
- Seiten – XAML-Dateien und deren Codebehind definieren die Benutzeroberfläche und verweisen auf die ViewModels und das PCL-Projekt, um Daten anzuzeigen und zu sammeln.
- Bilder – Begrüßungsbildschirm, Hintergrund- und Symbolbilder sind ein wichtiger Bestandteil der Benutzeroberfläche.
MainPage
Die MainPage-Klasse verwendet die TaskListViewModel
Daten zum Anzeigen von Daten mithilfe der Datenbindungsfeatures von XAML. Die Seite DataContext
ist auf das Ansichtsmodell festgelegt, das asynchron aufgefüllt wird. Die {Binding}
Syntax im XAML bestimmt, wie die Daten angezeigt werden.
TaskDetailsPage
Jede Aufgabe wird angezeigt, indem sie den TaskViewModel
xaml-Code binden, der in der TaskDetailsPage.xaml definiert ist. Die Vorgangsdaten werden über die TaskItemManager
In business Layer abgerufen.
Ergebnisse
Die resultierenden Anwendungen sehen auf jeder Plattform wie folgt aus:
iOS
Die Anwendung verwendet iOS-Standard-Benutzeroberflächendesign, z. B. die Schaltfläche "Hinzufügen", die in der Navigationsleiste positioniert wird, und das integrierte Plussymbol (+). Außerdem wird das Standardmäßige UINavigationController
Verhalten der Schaltfläche "Zurück" verwendet und "Wisch-zu-Löschen" in der Tabelle unterstützt.
Android
Die Android-App verwendet integrierte Steuerelemente, einschließlich des integrierten Layouts für Zeilen, für die ein "Teilstrich" angezeigt werden muss. Das Hardware-/Systemrückverhalten wird zusätzlich zu einer Schaltfläche "Zurück" auf dem Bildschirm unterstützt.
Windows Phone
Die Windows Phone-App verwendet das Standardlayout, wobei die App-Leiste am unteren Bildschirmrand anstelle einer Navigationsleiste oben auffüllt wird.
Zusammenfassung
Dieses Dokument enthält eine ausführliche Erläuterung, wie die Prinzipien des mehrschichtigen Anwendungsdesigns auf eine einfache Anwendung angewendet wurden, um die Wiederverwendung von Code auf drei mobilen Plattformen zu erleichtern: iOS, Android und Windows Phone.
Es hat den Prozess beschrieben, der zum Entwerfen der Anwendungsebenen verwendet wird, und erläutert, welche Code- und Funktionalität in jeder Ebene implementiert wurde.
Der Code kann von github heruntergeladen werden.