Code Sharing zwischen WPF und Metro Anwendungen

Florian Rappl, Microsoft MVP Visual C#

Code Sharing mit C#

Windows Desktop und Windows Store

Sharing

Agenda

  1. 08:30 - 10:00 Vortrag (Erster Teil)
  2. 10:00 - 10:30 Pause
  3. 10:30 - 12:00 Vortrag (Zweiter Teil)
  4. 12:00 - 13:00 Mittagspause
  5. 13:00 - 16:30 Diskussion Relationsansicht
  6. 16:30 - 18:00 Offener Teil

Vergleich der Plattformen

WPF (aka Avalon)
  • Keine Store Aufnahme möglich
  • Kein WinRT Support
  • Voller Zugriff auf Windows
  • Unzählige Features
  • Mäßige (Multi-)Touch Umsetzung
Modern Style (aka Metro)
  • Können im Store platziert werden
  • Laufen auch auf WinRT
  • Stark eingeschränkter Zugriff
  • Eher leichtgewichtig
  • Sehr gute Touch Unterstützung

Übergang von WPF zu Metro

  • Management des Application Life Cycles notwendig (z.B. Wiederherstellen des Zustandes)
  • Charms und Contracts, z.B. für die Suche
  • Live Tiles und Notifications sollten verwendet werden
  • Interaktion mit Sensoren möglich über die neue Sensors API
  • Asynchrone Programming mit await / async ist aufgrund der API Pflicht

The Good

  • Mit C# kann man beide Systeme ansprechen
  • Das Visual Studio kann für beides verwendet werden
  • Bestehender Code kann verlinkt werden
  • Von Dritten unabhängiger Code läuft sofort
  • Portable Class Libraries unterstützen uns

The Bad

  • Vom .NET-Framework steht nur eine Untermenge zur Verfügung
  • APIs sind zum Teil unterschiedlich
  • Portable Class Libraries sind häufig zu eingeschränkt
  • Externe Bibliotheken sind im Regelfall Plattformabhängig

The Ugly

  • XAML ist oberflächlich nahezu identisch, die Controls sind es keineswegs
  • Selbe Bezeichner, andere Namespaces
  • Einschränkungen bei der Interaktion mit dem Nutzer
  • Anderes Modell für Resourcen
  • Metro: MVVM eingeschränkt im Vergleich zu WPF

Portable Class Libraries (PCL)

Features einer PCL

  • Nur gemeinsam vorhandene Features sind aktiv
  • Hängt stark von den gewählten Plattformen ab
  • Auch die Anzahl der unterstützten Systeme ist wichtig
  • Wichtig: keine unnötigen Plattformen auswählen
  • Die verschiedenen systemabhängigen Features sind auf MSDN zusammengefasst (msdn.microsoft.com/en-us/library/gg597391.aspx)

Warum PCL verwenden?

  • Immer Generalisierung vor Spezialisierung verwenden
  • PCL sollte eine Generalisierung der Anwendung(en) darstellen
  • Ziel: Maximierung der Generalisierung
  • Niemals tragbar für eine Anzeigetechnologie
  • Forciert Separation of Concerns

Beispielaufbau mit PCL(s)

→ 1 - PCL erstellen und nutzen

Konditionales Compilen

  • Läßt dieselbe Datei in unterschiedlichen Targets anders compilen
  • Baut auf dem Präprozessor auf
  • Ideal um einfache Änderungen am Code durchzuführen
  • Visuelle Hilfe im Visual Studio
  • Wird allerdings schnell unübersichtlich
  • Nicht sehr gut erweiterbar

Präprozessor Direktiven

				#define SYMBOL
				#if SYMBOL
				/* Code für SYMBOL */
				#elif OTHER_SYMBOL
				/* Code für OTHER_SYMBOL */
				#else
				/* Alternativer Code */
				#endif
			

Bereits vorhandene Direktiven

  • Im Regelfall verwendet man nicht #define
  • In den Projekteinstellungen setzt man die vorhandenen Symbole
  • Die Symbole sind Target spezifisch
  • z.B. standardmäßig für Debug dabei: DEBUG
  • Bei Windows Store: NETFX_CORE

Compilation mit Konditionalen

→ 2 - Konditionale einsetzen

Vererbung

  • Dringender als zuvor: Generellen Code in Basisklassen stecken
  • z.B. speziellen Code über Polymorphie einbinden
  • Geschickter Aufbau einer Vererbungshierarchie
  • Abstrakte Klassen um Spezialisierung zu forcieren
  • Strukturiert zur gleichen Zeit den Gesamtcode
  • Entkopplung von direkten Abhängigkeiten

SOLID Prinzipien

  • Stellen die Grundlage für Code-Sharing dar
  • Ziel der 5 Prinzipien: Hohe Wiederverwertbarkeit, geringe Kopplung
  • Identifikation von gemeinsamen Code
  • Allgemeiner: Sauberer Code (auch FCoI, KISS, DRY, ...)
  • Am wichtigsten für uns: OCP und DIP

Open Close Principle

  • Code sollte von den Instruktion abgeschlossen sein
  • Aber auch offen für Erweiterungen
  • Die Erweiterungen sollen primär über Daten möglich sein
  • Sekundär sollen auch Erweiterungen durch Vererbung möglich sein
  • Einfaches Beispiel: Factory über Dictionary statt Hardcoded

Dependency Inversion Principle

  • Abhängigkeiten sollen abstrahiert werden
  • Abstraktionen sollen nicht von (Implementierungs-) Details abhängen
  • Wie erzielen? Niemals konkrete Typen anfordern / erstellen
  • Immer in Properties oder im Konstruktor Abstraktionen (Interfaces) verlangen
  • Liefert außerdem ausgezeichnete Testbarkeit

Vom Allgemeinen zum Speziellen

→ 3 - OOP und SOLID

Partielle Klassen

  • Sehr gut um Konditionale zu ersetzen
  • Häufig dann geschickt, wenn man eine vorhandene Klasse komplett übernehmen kann
  • Funktionieren auch sehr gut mit Basisklassen
  • Hauptklasse für verlinkt, Erweiterung wird neu geschrieben
  • Ideal um komplette Methoden hinzuzufügen

Verknüpfungen nutzen

Noch mehr mit partiellen Klassen

  • Man ist nicht auf 2 Deklarationen (Primärdefinition, Erweiterung) beschränkt
  • Jede Deklaration kann auch noch weitere Interfaces implementieren
  • Schlüsselwörter können hinzugefügt, aber nicht entfernt werden (z.B. abstract, sealed, public, ...)

→ 4 - Partielle Klassen

Erweiterungsmethoden

  • Die letzte Instanz um inkompatiblen Code zu compilen
  • Erweiterungsmethoden kommen ideal bei verlinkten Dateien
  • Keine Änderungen an der Quelldatei notwendig
  • Einzige Bedingung: Signatur der Methode passt
  • Die Erweiterungsmethode(n) in einem Basisnamespace deklarieren

Reflection mit Erweiterungsmethoden

  • Überall verfügbar: GetType() und typeof()
  • Allerdings: Type Instanzen in Metro nahezu unbrauchbar
  • Reflection benötigt eine Instanz vom Typ TypeInfo
  • Entscheidung über Aussehen und Signatur je nachdem welches Projekt (WPF, Metro) als primär angesehen wird

Wichtig

  • Properties immer in Methoden auslagern um Erweiterungsmethoden anwenden zu können
  • Nach Möglichkeit keine Ergebnisse der Aufrufe von Erweiterungsmethoden zurückgeben
  • Alles Rückgaben mit var behandeln
  • Dies reduziert die Abhängigkeit auf den Rückgabetypen

→ 5 - Erweiterungsmethoden verwenden

Zusammenfassung

  • C# besitzt viele Möglichkeiten um Code für mehrere Plattformen zu schreiben
  • Grundsätzlich gilt: Der Code muss möglichst entkoppelt und frei von Abhängigkeiten sein
  • Code der auf SOLID Prinzipien aufbaut, kann fast ohne Aufwand umgestellt werden
  • Verschiedene Methoden für verschiedene Zwecke

Flashback

  • Portable Class Library
  • SOLID / OOP
  • Erweiterungsmethoden
  • Partielle Klassen
  • Konditionale

→ 6 - Zwei unterschiedliche Beispiele

Take aways

  • Code strukturieren
  • Gemeinsame Basis finden
  • Kleine Teile spezialisieren
  • UI unter Umständen mehrfach schreiben
  • Immer versuchen die PCL Lösung zu verwenden
  • Konditionale auf Klassen-Level durch partielle Klassen ersetzen

Diskussion: Cross-Platform Control

  • Sog. Relationsansicht
  • Gegenüberstellung von Textschnipseln
  • Spezielles Feature: Drag and Drop

Vielen Dank für Ihre Aufmerksamkeit!

MVP

Florian Rappl, Microsoft MVP Visual C#