Cross-Device-Entwicklung mit der Universal-Windows-Plattform

Windows 10: Ein Code, eine App – für alle Windows-Geräte
Kommentare

Ein Hochgenuss für Entwickler: Mit Windows 10 ist das Cross-Device-Konzept endlich erwachsen geworden. Es wird nur noch ein Code und ein App-Paket benötigt, um auf allen Windows-Geräten dabei sein zu können. Diesem Konzept folgt jetzt auch der neue, einheitliche Windows Store, der nun nicht mehr zwischen Smartphone, Desktop oder TV unterscheidet. Das spart Zeit und Geld. Der Gewinn ist eine größere Reichweite für Entwickler und mehr Komfort für den Anwender. In diesem Artikel entdecken wir gemeinsam das ausgereifte Konzept und einige weitere Leckerbissen.

Mit Windows 8.1 und Windows Phone 8.1 wurde das Universal-App-Konzept geboren. Das Konzept dahinter ist, so viel Code wie möglich wiederverwenden zu können. So bestand ein Universal-Windows-8.1-App-Projekt aus unterschiedlichen Welten. Darunter ein Windows-Phone -8.1- und ein Windows-8.1-Projekt. Eine gemeinsame Codebasis wurde zudem über ein drittes Shared-Projekt bereitgestellt. Zu guter Letzt wurde für jede Welt ein eigenständiges App-Paket kompiliert, das die.NET Assemblies mit dem eigenen Code beinhaltete. Diese Pakete mussten jeweils im Windows-8.1- und Windows Phone Store veröffentlicht werden. Für beide Stores war ein eigenständiger Entwickleraccount nötig, der durch eine einmalige Gebühr von Microsoft freigeschaltet wurde.

Aus einem Guss

Das hat sich unter Windows 10 stark verändert. Auf jedem Windows-10-Gerät befindet sich exakt der gleiche Kernel, womit die neue Universal-App nur noch aus einem Projekt und somit aus einem App-Paket besteht. Die Windows-10-Landschaft hat zudem eine gigantische Gerätereichweite erzielt. So läuft Windows 10 auf dem klassischen Desktop-PC und Notebook. Mobil ist es auf Tablets und Smartphones unterwegs. Im TV-Bereich haben wir die Xbox und den neuen Surface Hub. Sogar für das Internet of Things (IoT) ist es für Raspberry Pi, Intel Edison und Microsoft Band vertreten. Zukünftig ebenfalls für die holografische Datenbrille HoloLens (Abb. 1).

Abb. 1: Die Windows-10-Landschaft

Abb. 1: Die Windows-10-Landschaft

In bester Form mit .NET Native

Das universale App-Paket beinhaltet die von uns entwickelten .NET Assemblies. Dass diese allerdings zukünftig auf jedem Gerät die beste Kompatibilität und Performance erhalten, ist technisch betrachtet gar nicht so einfach. Dazu hat Microsoft ein neues Konzept mit .NET Native eingeführt. Beim Einreichen des App-Pakets in den Store wird in der Cloud aus den .NET Assemblies nativer Code kompiliert.

Das bedeutet, es wird kein JIT-Compiler zur Laufzeit nötig sein. Auf diese Weise wird unter anderem ein bis zu 60 Prozent schnellerer Start der App ermöglicht und wertvolle Akkulaufzeit eingespart. Der Speicherverbrauch wird auch stark reduziert, da beim Kompilieren ungenutzte Typen und Funktionen entfernt werden. Das sind bis zu 30 Prozent, die an Speichereinsparung dazugewonnen werden können.

Also kurz zusammengefasst, mit .NET Native nutzen Windows-10-Apps keine Laufzeitumgebung mehr und das steigert die gesamte Qualität enorm.

Tipps bei der Entwicklung mit .NET Native

Bei der Entwicklung wird mit der Standard-Debug-Konfiguration noch keine .NET-Native-Kompilierung ausgeführt. Das holt zur Entwicklungszeit einiges an Performance heraus und verbessert die Debugging-Unterstützung. Dennoch sollte man in regelmäßigen Abständen auf die Releasekonfiguration wechseln, um sicherzustellen, dass auch keine unerwünschten Seiteneffekte unter .NET Native auftreten. Das ist leider die unschöne Seite der Medaille.

Brücken bauen zwischen den Kulturen

Die klassische Desktop-Entwicklung bleibt wie bei Windows 8.1 bestehen. So hat Microsoft offiziell bekanntgegeben, dass an WPF weiter entwickelt wird. Es wurde sogar als die Top-Technologie für eine professionelle Desktop-Entwicklung angepriesen. Aus der App-Welt hat sich hierbei eine weitere Brücke aufgebaut. Es ist jetzt mit sogenannten „Bridging- Technolgien“ möglich, das Object C (iOS), Java (Android), Win32 (Desktop) und das klassische Web zu Universal Windows-Apps fundieren zu können. Dieser geniale Schachzug von Microsoft ist gerade für die Konkurrenz der anderen Plattformen schmerzhaft.

Neues Design trifft auf bewährte Plattformen

Hand aufs Herz, die von Windows 8 eingeführte Microsoft Design Language, die erst als Metro-Design vorgestellt wurde, hat einige innovative Änderungen gebracht. Andere Plattformen wie Android oder iOS haben hier erst spät nachgezogen. Dennoch liegen Android und iOS gegenüber Windows im mobilen Markt weit vorne. Nun öffnet sich Windows 10 mit den bereits erwähnten „Bridging-Technologien“ und eine Android- oder iOS-App hat nun einmal nicht die Möglichkeit, auf eine Charms Bar zuzugreifen. Die Entwickler müssten einen zu hohen Zeitaufwand investieren, um ihre bisherige Welt unter Windows 10 einbringen zu können.

Schnell und überall: Datenzugriff mit Entity Framework Core 2.0

Dr. Holger Schwichtenberg (www.IT-Visions.de/5Minds IT-Solutions)

C# 7.0 – Neues im Detail

Christian Nagel (CN innovation)

Ein weiteres Problem für Microsoft war die User Experience der meisten Benutzer weltweit. Diese haben die Bedienkonzepte von Android und iOS stark verinnerlicht. Oft beeinflusst gerade dieser Aspekt die Kaufentscheidung. Aus diesem Grund hat sich die Microsoft Design Language weiterentwickelt in Version 2 und zwar in die Richtung der bewährten Plattformen (Abb. 2).

Abb. 2: Unterschiede zu anderen Plattformen

Abb. 2: Unterschiede zu anderen Plattformen

So gibt es unter Windows 10 keine Charms Bar mehr. Als allgemeines Menü wurde das Hamburger-Menü eingeführt, das sich wie bei anderen Plattformen links oben befindet. Die bekannten Menüpunkte mit einem Kreis außen rum haben sich ebenfalls verabschiedet. So setzt man nur noch auf klassische Piktogramme ohne Kreis. Dazu gibt es unter Windows 10 eine neue Schriftart „Segoe MDL 2 Assets“ mit zahlreichen neuen Icons, die direkt in die App eingebunden werden können. Die Standardsteuerelemente wie der DateTimePicker und TimePicker sind jetzt exakt die gleichen. Bei Windows Phone 8.1 und Windows 8.1 hingegen waren sie noch unterschiedlich.

Universell denken mit Adaptive Design

Für die Oberflächen der unterschiedlichen Geräte wird es kein eigenständiges Projekt mehr geben. Die Lösung ab Windows 10 lautet „Adaptive Design“. So muss man in seiner XAML-Datei das Layout für unterschiedliche Gerätegrößen hinterlegen. Um das zu vereinfachen, gibt es eine empfohlene Pixeleinheit und einige neue Layoutsteuerelemente.

Unterschiedliche Smartphones mit der gleichen Gerätegröße können dagegen unterschiedliche Auflösungen beanspruchen. Nun soll aber die Windows-10-App auf allen Geräten die gleiche Größe und Bedienbarkeit bieten, ganz gleich, ob es sich hierbei um ein Smartphone, Tablet oder ein TV handelt. Als Beispiel: Hält man das Smartphone bequem von der Couch aus neben das TV, dann sollten die Steuerelemente auf beiden Geräten gleich groß wirken. Auch wenn die Steuerelemente auf dem TV durch die Entfernung größer gemacht wurden, um diesen Effekt zu erzeugen (Abb. 3).

Abb. 3: App-Design muss auf allen Geräten gleich groß aussehen

Abb. 3: App-Design muss auf allen Geräten gleich groß aussehen

Bei dieser Anforderung beginnt sofort der Pixelchaosmarathon für Entwickler und das nimmt deutlich viel Spaß. Zur Abhilfe empfiehlt Microsoft die Skalierung mit der Pixeleinheit namens „Effektive Pixel“ (kurz: Epx). Eine komplette Übersicht der effektiven Pixeleinheiten für die unterschiedlichen Geräte zeigt Tabelle 1. Ein weiterer Aspekt ist Microsofts neue Faustregel: Das Vielfache von vier. So sollte etwas weniger weißer Raum für den Inhalt in Betracht gezogen werden und man sollte die Abstände jeweils mit vier multipliziert ausrichten. Zum Beispiel soll man ein 16-px-Icon innerhalb von einem 48px-Button zentriert darstellen (Abb. 4).biswanger_crossdevice_tab_1

Abb. 4: Neue Regel: Das Vielfache von vier

Abb. 4: Neue Regel: Das Vielfache von vier

Adaptives Layout mit Relative Panel

Das Relative Panel ist eines der neuen Layoutsteuerelemente. Bei diesem erhält jedes Kinderelement einen Namen. Zusätzlich werden ein oder mehrere Attached-Properties von RelativePanel deklariert. Dieses bietet weitere Eigenschaften dazu an, zu welchen Elementen das aktuelle Element relativ ausgerichtet werden soll. In Listing 1 wird das durch zwei Rechtecke demonstriert. Ein rotes und ein blaues. Das blaue Rechteck erhält hierbei die Deklaration, dass es direkt unterhalb des roten Rechtecks positioniert werden soll. Eine weitere Deklaration mit AlignRightWith gibt an, dass es zudem am rechten Ende vom gewünschten roten Rechteck ausgerichtet wird. In Abbildung 5 sieht man das gewünschte Ergebnis.

Listing 1: Das „RelativePanel“-Steuerelement
<RelativePanel> 
  <Rectangle x:Name="Red" Height="100" Width="200" Fill="Red"/>
  <Rectangle x:Name="Blue" Height="100" Width="150" Fill="Blue"
    RelativePanel.Below="Red"
    RelativePanel.AlignRightWith="Red"/>
</RelativePanel>
Abb. 5: Das neue „RelativePanel“-Steuerelement im Einsatz

Abb. 5: Das neue „RelativePanel“-Steuerelement im Einsatz

Das RelativePanel-Steuerelement vereinfacht das Layouten enorm. Dennoch ist es wichtig zu wissen, welche Fallstricke es für Entwickler gibt. Ändert man etwa das AlignRightWith-Property aus Listing 1 zu LeftOf, hätte dies zur Folge, dass das blaue Rechteck direkt links unterhalb des roten Rechtecks positioniert wird. Die Praxis zeigt allerdings genau das Gegenteil. Das blaue Rechteck verschwindet komplett vom Bildschirm. Das liegt daran, dass der Standardwert aller RelativePanel-Kindelemente Top oder Left erhalten. Horizontal für Top und vertikal für Left. Definiert man nun einen Wert, der für einen Standardwert bereits vorhanden ist, wird automatisch das Element ausgeblendet. Das ist aktuell noch ein unerwünschter Effekt.

Stellen Sie Ihre Fragen zu diesen oder anderen Themen unseren entwickler.de-Lesern oder beantworten Sie Fragen der anderen Leser.

Die Verarbeitung der Reihenfolge spielt hierbei ebenfalls eine große Rolle. So wird die Ausrichtung vom Panel als erstes verarbeitet (AlignTopWithPanel, AlignLeftWithPanel etc.). Die Ausrichtung von Geschwisterelementen an zweiter Stelle (AlignTopWith, AlignLeftWith etc.). Das direkte Positionieren von Geschwisterelementen wird zuletzt vorgenommen (Above, Below, RightOf, LeftOf).

Wichtig zu wissen, ist außerdem: Ein gegenseitiger Verweis führt zur Laufzeit zu einer Exception. Zum Beispiel wenn man in Listing 1 beim roten Rechteck zusätzlich

RelativePanel.Above="Blue"

hinzufügen würde.

Dynamisch mit den Adaptive Triggers

Das RelativePanel-Steuerelement zeigt, wie einfach das Ausrichten und Positionieren von Steuerelementen sein kann. Soll die Oberfläche passend zu den vorgeschlagenen effektiven Pixeln ausgerichtet werden, müssen die RelativePanel-Kindelemente dynamisch verändert werden, sodass sich die Oberfläche eines Smartphones an die eines großen TV-Bildschirms anpasst. Dazu wurden unabhängig vom neuen Steuerelement die Adaptive Triggers eingeführt. Diese erweitern das bisher bekannte Visual-State-Managerkonzept.

Visual States definieren die unterschiedlichen Zustände von Steuerelementen. Ein bekanntes Beispiel wäre der Button, der die Zustände von Normal, Focus oder Clicked hat. Der neue Adaptive Trigger bekommt jetzt via Epx die Regeln dazu mitgeteilt, ab welcher Bildschirmbreite ein bestimmter Zustand aktiviert werden soll.

In Listing 2 wird gezeigt, wie durch Adaptive Trigger das Verhalten der Rechtecke auf einem Smartphone und Tablet festgelegt wird. Das Ganze lässt sich beim Debuggen ausprobieren. Hier erscheint unter Windows 10 standardmäßig die App als Windows-Fenster. Beim Ändern der Fenstergröße wird automatisch der Inhalt angepasst. Ebenso kann ein Test im jeweiligen Geräteemulator stattfinden. Abbildung 6 zeigt, dass sich die Rechtecke bei einem Smartphone untereinander befinden; ab Tabletgröße werden diese linear dargestellt.

Listing 2: Das „RelativePanel“-Steuerelement mit Adaptive Trigger
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
  <VisualStateManager.VisualStateGroups>
    <VisualStateGroup>
      <VisualState x:Name="Smartphone">
        <VisualState.StateTriggers>
          <AdaptiveTrigger MinWindowWidth="320" />
        </VisualState.StateTriggers>
        <VisualState.Setters>
          <Setter Target="Blue.(RelativePanel.Below)" Value="Red" />
          <Setter Target="Blue.(RelativePanel.AlignRightWith)" Value="Red" />
        </VisualState.Setters>
      </VisualState>
      <VisualState x:Name="Tablet">
        <VisualState.StateTriggers>
          <AdaptiveTrigger MinWindowWidth="640" />
        </VisualState.StateTriggers>
        <VisualState.Setters>
          <Setter Target="Blue.(RelativePanel.Below)" Value="" />
          <Setter Target="Blue.(RelativePanel.AlignRightWith)" Value="Red" />
        </VisualState.Setters>
      </VisualState>
    </VisualStateGroup>
  </VisualStateManager.VisualStateGroups>

  <RelativePanel>
    <Rectangle x:Name="Red" Height="100" Width="200" Fill="Red" />
    <Rectangle x:Name="Blue" Height="100" Width="150" Fill="Blue" 
      RelativePanel.Below="Red"
      RelativePanel.AlignRightWith="Red" />
  </RelativePanel>
</Grid>
Abb. 6: Das „RelativePanel“-Steuerelement auf dem Smartphone und Desktop

Abb. 6: Das „RelativePanel“-Steuerelement auf dem Smartphone und Desktop

Bye bye Charms Bar, hallo Split View!

Die Charms Bar hat sich unter Windows 10 verabschiedet. Trotz großem Abschiedsschmerz meinerseits muss es weitergehen, und zwar mit dem neuen Hamburger-Menü. Dieses wird unter Universal Windows-Apps mit dem SplitView-Steuerelement bereitgestellt. Das Konzept besagt, dass die Menüpunkte ausgeblendet werden. Zum manuellen Öffnen und Schließen wird ein Button mit dem berühmten Hamburger-Icon angeboten. Nur muss der Entwickler die ganze Darstellung mit dem SplitView-Steuerelement komplett selbst implementieren. In Listing 3 und 4 wird der dazugehörige Code gezeigt, in Abbildung 7 findet sich die passende Darstellung dazu. Wie im Code ersichtlich wird, erhält der Button nicht wie unter Windows 8.1 gewohnt ein Icon über die Ressourcen, sondern über die eingangs erwähnte Schriftart. Es ist also nur ein ungewohnter Umweg. Der ASCI-Code innerhalb der Schriftart wird über das Content-Property festgelegt. Der Rest vom ausklappbaren Inhalt erfolgt beim SplitView.Pane. Die SplitView ist dazu leichtgewichtig und selbsterklärend.

Listing 3: Das „SplitView“-Steuerelement als neues Menü
<SplitView x:Name="MySplitView" DisplayMode="CompactOverlay" IsPaneOpen="False" CompactPaneLength="50" OpenPaneLength="150">
  <SplitView.Pane>
    <StackPanel Background="Gray">
      <Button x:Name="HamburgerButton" FontFamily="Segoe MDL2 Assets" Content="" Width="50" Height="50" Background="Transparent" Click="HamburgerButton_Click"/>
      <StackPanel Orientation="Horizontal">
        <Button FontFamily="Segoe MDL2 Assets" Content="" Width="50" Height="50" Background="Transparent"/>
        <TextBlock Text="Button 1" FontSize="18" VerticalAlignment="Center" />
      </StackPanel>
      <StackPanel Orientation="Horizontal">
        <Button FontFamily="Segoe MDL2 Assets" Content="" Width="50" Height="50" Background="Transparent"/>
        <TextBlock Text="Button 2" FontSize="18" VerticalAlignment="Center" />
      </StackPanel>
      <StackPanel Orientation="Horizontal">
        <Button FontFamily="Segoe MDL2 Assets" Content="" Width="50" Height="50" Background="Transparent"/>
        <TextBlock Text="Button 3" FontSize="18" VerticalAlignment="Center" />
      </StackPanel>
    </StackPanel>
  </SplitView.Pane>
  <SplitView.Content>
    <Grid>
      <TextBlock Text="SplitView Basic" FontSize="54" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
  </SplitView.Content>
</SplitView>
Listing 4: Bei Hamburger-Button-Klick „SplitView“-Menü öffnen und schließen
private void HamburgerButton_Click(object sender, RoutedEventArgs e)
{
  MySplitView.IsPaneOpen = !MySplitView.IsPaneOpen;
}
Abb. 7: Das „SplitView“-Steuerelement als neues Menü

Abb. 7: Das „SplitView“-Steuerelement als neues Menü

Adaptive Code

Wie wir die Oberfläche passend für alle Geräteklassen adaptiv gestalten, haben wir bereits erfahren. Jedoch gibt es technische Einschränkungen, denen Windows 10 selbst ausgeliefert ist. So gibt es Funktionen für Smartphones, die ein Desktopcomputer oder TV nicht bieten kann. Ein Beispiel wäre die Vibrationsmöglichkeit von Smartphones. Die gibt es nicht einmal auf All-in-One- Desktopcomputern. Dennoch soll eine solche Funktionalität in die zukünftige Universal Windows-App integriert werden. Bei dieser Situation kommt Adaptive Code ins Spiel.

Zu Beginn müssen die gerätespezifischen Funktionen im eigenen Projekt bereitgestellt werden. Für Smartphones befinden sich diese unter Windows Mobile Extensions for the UWP. Diese sind unter den Referenzen beim Universal Windows-Tab unter Erweiterungen zu finden.

Für die Vibration sind lediglich zwei Zeilen Code nötig. Wird dieser Code allerdings bei einem Gerät ohne die entsprechende Hardware ausgeführt, erhalten wir eine unschöne System.TypeLoadException und die Universal-Windows-App stürzt ab. Um dieser Situation aus dem Weg gehen zu können, muss eine zusätzliche IF-Abfrage den entsprechenden Bereich schützen. Die ApiInformation.IsTypePresent-Methode ermöglicht eine Überprüfung dahingehend, ob der gewünschte Typ auf dem Gerät verfügbar ist. Etwas unschön hierbei ist die fehlende Typsicherheit. Es muss exakt der gesamte Namespace und die gewünschte Klasse als String-Wert überreicht werden. Technisch könnte ein Try-Catch-Block helfen, was allerdings zur Laufzeit hässliche Performanceprobleme verursacht. In Listing 5 wird der komplette Code zur Abfrage mit Vibration gezeigt.

Listing 5: Abfrage mit Vibration
if(ApiInformation.IsTypePresent("Windows.Phone.Devices.Notification.VibrationDevice"))
{
  var vibrationDevice = Windows.Phone.Devices.Notification.VibrationDevice.GetDefault();
  vibrationDevice.Vibrate(TimeSpan.FromSeconds(5));

Compiled Data Binding

Das Data Binding unter XAML war schon seit der ersten Geburtsstunde ein Highlight. Endlich eine vernünftige Lösung zur Trennung von Beschreibungslogik und Codelogik. Sogar die führende Webwelt übernimmt dieses Konzept und macht Frameworks wie AngularJS zum Superstar. Aber es gibt eben auch die dunkle Seite der Macht. So wird das Data Binding erst zur Laufzeit instanziiert. An welcher Stelle dann eventuell eine fehlerhafte Zuweisung stattfindet, ist nicht immer sofort ersichtlich und eine Fehlersuche wird damit erheblich erschwert. Nicht nur das, sondern das Data Binding wird ebenfalls zur Laufzeit mit Reflection instanziiert, was Speicher und Zeit kostet. Für große Anwendungen bedeutet das zusätzliche Performanceeinbußen.

Genau diese Schmerzen werden mit dem neuen Compiled-Data-Binding-Feature genommen. Wie der Name bereits verrät, wird das Binding beim Kompilieren fest verknüpft. Das verbessert nicht nur die Performance, sondern bietet ein typsicheres Arbeiten. Zum Beispiel wirft Visual Studio einen Kompilierungsfehler, wenn ein Binding nicht aufgelöst werden kann.

Für das neue Binding-Feature wird die klassische Binding-Syntax durch eine x:Bind-Syntax ersetzt. Geändert hat sich zudem der Standardwert für den Binding-Mode. Dieser ist bei Compiled Data Binding auf „One-Time“ gesetzt. Das bedeutet, dass die Daten nur einmalig vom ViewModel zur Oberfläche geladen werden. Weitere Änderungen auf der Oberfläche oder beim ViewModel werden ignoriert. Aus Performancegründen ist das oftmals elegant, aber nicht immer erwünscht. Zum Ändern des Standardwerts, schreibt man zusätzlich Mode=OneWay, das die Änderungen vom ViewModel zur Oberfläche weiterreicht, oder Mode=TwoWay für beide Richtungen. Das ist ein neuer Schritt, den man jetzt nicht mehr auslassen kann.

Eine feste Bindung kann wie gewohnt mit Properties erfolgen. Der ungewohnte Aspekt hierbei ist, dass dies nur auf die Code-Behind der aktuellen View beschränkt ist. Beim Einsatz des MVVM-Patterns wird bei der Code-Behind ein ViewModel-Property angelegt und das Compiled Data Binding funktioniert. So schlimm ist dieser Umweg nicht, denn für die Navigation und für das Verarbeiten von Dialogen musste ohnehin das ViewModel in der Code-Behind angezapft werden. Listing 6 und 7 zeigen den Einsatz des Compiled Data Bindings in Kombination mit dem MVVP-Pattern.

Listing 6: Das neue Compiled Data Binding mit OneWay Mode
 <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
   <TextBlock Text="{x:Bind ViewModel.Message, Mode=OneWay}" FontSize="42" />
 </StackPanel>
Listing 7: „ViewModel“-Instanz über Property bereitstellen
public sealed partial class MainPage : Page
{
  public MainPageViewModel ViewModel { get; set; }

  public MainPage()
  {
    this.InitializeComponent();

    ViewModel = new MainPageViewModel();
  }
}

DataTemplates mit Compiled Data Binding

Das Compiled-Data-Binding-Feature reagiert nicht mehr auf das klassische Data Context, sondern nur noch auf Properties der Code-Behind, die zur Kompilierungszeit zur Verfügung stehen. Das ist natürlich ein Problem für den Einsatz von Data Templates. Diese reagieren auf Bindings innerhalb vom Data Context. In Listing 8 sieht man die neue x:DataType-Syntax, die bei diesem Problem aushilft. Somit erkennt der Compiler, dass es sich um ein Compiled Data Binding handelt und kann das Binding für das Inhaltssteuerelement optimal auflösen.

Listing 8: Data-Templates mit Compiled Data Binding
<ListView ItemsSource="{x:Bind ViewModel.Customers, Mode=OneWay}">
  <ListView.ItemTemplate>
    <DataTemplate x:DataType="local:Customer">
      <StackPanel Margin="50">
        <TextBlock Text="{x:Bind FirstName}" />
        <TextBlock Text="{x:Bind LastName}" />
      </StackPanel>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

Data Binding auf Events

Für alle Leser, die das neue Compiled-Data-Binding-Feature zelebrieren, gibt es einen weiteren Adrenalinschub. Ihnen bietet sich nun endlich ein lang ersehntes Feature: Data Binding auf Events. So kann jedes Event der UserControls auf Methoden gebunden werden – mit oder ohne EventArgs. Das ist ein großer Feind für Behaviors und das unbeliebte ICommand rückt immer mehr in den Schatten. Das Festlegen des Binding-Modes ist hierbei übrigens nicht nötig. Listing 9 und 10 zeigen, wie ein Button-Klick eine Logik im ViewModel auslöst.

Listing 9: Compiled Data Bindings unterstützen das Binden auf Events
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
  <TextBlock Text="{x:Bind ViewModel.Message, Mode=OneWay}" FontSize="42" />
  <Button Content="OK" Click="{x:Bind ViewModel.SayHello}" />
</StackPanel>
Listing 10: ViewModel mit Methode, die von Compiled Data Binding aufgerufen wird
public class MainPageViewModel : INotifyPropertyChanged
{
  private string _message { get; set; }
  public string Message
  {
    get { return _message; }
    set
    {
      _message = value;
      OnPropertyChanged();
    }
  }

  private void OnPropertyChanged([CallerMemberName] string propertyName = null)
  {
    var handler = PropertyChanged;
    if(handler != null)
    {
      handler(this, new PropertyChangedEventArgs(propertyName));
    }
  }

  public void SayHello()
  {
    Message = "Hallo Windows 10 App";
  }

  public event PropertyChangedEventHandler PropertyChanged;
}

Noch mehr Speed beim Rendern mit „x:Phase“ und „x:Defer“

Ab Windows 10 wurde nochmals einiges an Geschwindigkeit herausgeholt. So sind einige Steuerelemente um einiges schneller als unter Windows 8.1, zum Beispiel rendert der Text sogar 50 Prozent schneller als beim Vorgänger. Neue Features ermöglichen zudem eine bessere Kontrolle beim Rendern.

Ein großes Problem waren Listen mit komplexem Inhalt. Zahlreiche Grafiken, ValueConverter und das Laden von Daten verzögerten die Darstellung enorm. Mit dem neuen x:Phase-Attached– Attribut kann man nun einzelnen DataTemple-Elementen eine Render-Priorisierung mitgeben, sodass der Benutzer bereits die ersten wichtigen Informationen sieht und weitere Daten nachträglich geladen werden. Das ist der gleiche Effekt, den Webbrowser wie Google Chrome schon lange bieten. Für den Benutzer erscheint die App somit deutlich schneller, obwohl diese noch nicht mit ihrer Arbeit fertig ist. Das Rendern wird hierbei in Phasen aufgeteilt. Die erste Phase beginnt mit 0, dies ist auch der Standardwert für alle Steuerelemente. Daraufhin kommt jede weitere definierte Phase an die Reihe. Die folgenden Codefragmente zeigen ein Data-Template, das erst den Produktnamen anzeigt und anschließend den Preis.

<DataTemplate x:DataType="local:Product">
  <Grid Height="100" Width="200">
    <TextBlock Text="{x:Bind Name}" />
    <TextBlock Text="{x:Bind Price}" x:Phase="1" />
  </Grid>
</DataTemplate>

Je nach Leistung des Geräts bemerkt der Benutzer eine verzögerte Darstellung vom Preis. In den meisten Fällen sind es hierbei Smartphones. Um x:Phase auch außerhalb von DataTemplates nutzen zu können, gibt es das IncrementalUpdateBehavior in Microsoft Expression Blend.

Oft existieren Steuerelemente, die zu Beginn ausgeblendet werden und nur zu speziellen Fällen erscheinen sollen. In diesem Fall wird dennoch ein Rendern ausgelöst, das die Startzeit und Bedienbarkeit verzögern kann. Das neue x:Defer-Attached-Attribut bietet hierbei eine Lazy-Loading-Funktionalität. Das bedeutet, der Entwickler muss manuell im Code festlegen, ab wann das Steuerelement wirklich instanziiert werden soll, d. h., ab wann er es also wirklich benötigt.

Die Bedingung dazu ist, dass das gewünschte Steuerelement einen Namen tragen muss. Dieser wird dazu benötigt, die Instanz kontrolliert anstoßen zu können. Zusätzlich muss das Steuerelement das Attribut x:DeferLoadStrategy=“Lazy“ erhalten. Für die kontrollierte Instanziierung wird in der Code-Behind-Datei die FindName-Methode aufgerufen, die dann den Namen vom Steuerelement benötigt. Diese sorgt für eine sofortige Instanziierung und die Oberfläche beginnt mit dem Rendervorgang. Listing 11 und die nachfolgenden Codefragmente veranschaulichen das Beispiel. Die Codeschnipsel zeigen zudem, wie die Instanziierung mit der FindName-Methode ausgelöst wird.

private void OnButtonClick(object sender, RoutedEventArgs e)
{
  this.FindName("Details");
}
Listing 11: Details-Grid per Lazy Loading instanziieren
<Grid x:Name="Details" x:DeferLoadStrategy="Lazy">
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="Auto" />
  </Grid.ColumnDefinitions>

  <TextBlock Text="{x:Bind Description}" />
  <TextBlock Grid.Column="1" Text="{x:Bind Price}" />
  <TextBlock Grid.Row="1" Text="{x:Bind Company}" />
  <TextBlock Grid.Row="1" Grid.Column="1" Text="{x:Bind Support}" />
</Grid>
<Button Content="Zeige Details" Click="OnButtonClick"/>

Jetzt durchstarten

Für die Entwicklung wird Visual Studio 2015 benötigt. EinKauf der großen Version dürfte allerdings nicht nötig sein. Die neue kostenlose Community-Edition bietet ebenfalls alles, was man für die Windows-10-App-Entwicklung benötigt. Idealerweise hat man auch Windows 10 installiert, was sogar nicht notwendig ist. Der Entwicklungskomfort ohne Windows 10 lässt allerdings stark nach. So wird kein XAML-Designer unterstützt und das Debuggen funktioniert nur remote über ein Windows-10-Gerät. Die neue Projektvorlage ist unter Windows | Universal zu finden. Allerdings gibt es diesmal keine fertigen Templatevorlagen mit bestehendem Inhalt.

Dieser Artikel hat die größten Highlights aus der schönen neuen Welt präsentiert. Wer nun Geschmack daran gefunden hat, noch mehr zum Thema zu hören und zu sehen, dem kann ich das kostenlose Videotraining bei der Microsoft Virtual Academy ans Herz legen. Hier zeigen die Microsoft-Technical-Evangelisten Oliver Scheer, Daniel Meixner und Patric Boscolo in über fünf Stunden alle weiteren relevanten Informationen. Beispielcode für viele neue Features gibt es zudem kostenlos auf GitHub.

Fazit

Bei meinem letzten großen Artikel zur Universal-App-Entwicklung unter Windows 8.1, schrieb ich im Fazit folgende Fragen zur Zukunft: „Schafft es Microsoft die Welten noch enger zusammen zu bringen? Werde ich das neue Sprachfeature von Windows Phone Cortana, auch unter Windows bekommen? Erhält mein Windows Tablet dann auch eine Action Bar? Wird aus Universal Windows-Apps mehr als eine Shared-Projektvorlage? Es bleibt also spannend!“.

Dieser Artikel hat einige meiner Prognosen wieder einmal bestätigt und mein Entwicklerherz getroffen. Wir haben jetzt deutlich mehr als nur eine Shared-Projektvorlage. Zahlreiche Neuerungen wären für die klassische WPF-Entwicklung von hohem Interesse. Nur baut WPF nicht auf .NET Native auf und das macht es für Microsoft selbst gar nicht so einfach. Falls der Artikel bei Ihnen noch einige Fragen offen gelassen hat, können Sie mir gerne jederzeit eine E-Mail an gregor.biswanger@cleversocial.de schreiben. Ich wünsche nun viel Spaß beim Programmieren für alle Windows-Geräte mit nur wenig Aufwand und eine ordentliche Portion Freude.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -