Moderne Rich Internet Applications erreichen nicht nur eine beachtliche Funktionsvielfalt sondern auch eine durchaus spürbare Dateigröße, die das Vorausladen der Inhalte und die Visualisierung des Ladeprozesses erforderlich macht. Das ist bei Silverlight nicht anders als bei Flash. Doch Silverlight verhält sich ein wenig anders als Flash und hat auch mit „Splash Screen“ gleich einen anderen Namen dafür erhalten.
Ein Splash Screen ist kein Bestandteil der Anwendung sondern wird unabhängig als splashscreensource-Parameter des Silverlight PlugIns im HTML-Dokument gesetzt. Das hat den Vorteil, dass zu jeder Zeit ein „Preloader“ zu einer Silverlight-Anwendung hinzugefügt werden kann, ohne dass dies die eigentliche Anwendung in irgendeiner Form beeinflusst. Aber genau darin liegt auch der Nachteil: Es werden keine Ressourcen geteilt und es ist auch kein fließender Übergang vom Splash Screen zur Anwendung möglich. Sollte das erforderlich sein, dann ist ein „Stub Loader“, also eine möglichst kleine Anwendung erforderlich, die sich explizit um das Nachladen der dann vermutlich Bandbreiten verschlingenden Reste kümmert. Dieses Verfahren mit einer möglichst leichtgewichtigen Startanwendung ist so übrigens auch in der Flash-Welt durchaus gängig! Für einfache Anforderungen ist aber der Splash Screen nützlich und außerdem leicht implementiert.
Die Angabe der von Silverlight zu nutzenden XAML-Datei (keine XAP-Datei sondern wie bei Silverlight 1 ein XAML-Dokument) sowie die zugehörigen optionalen Ereignis-Handler für den Ladefortschritt (onSourceDownloadProgressChanged) und den Abschluss des Ladevorgangs (onSourceDownloadComplete) erfolgen im HTML-Dokument.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <object data="data:application/x-silverlight," type="application/x-silverlight-2-b2" width="100%" height="100%">
<param name="source" value="ClientBin/Application.xap"/>
<param name="onerror" value="onSilverlightError" />
<param name="background" value="white" />
<!-- Preloader Controller -->
<param name="splashscreensource" value="Preloader.xaml"/>
<param name="onSourceDownloadProgressChanged" value="onSourceDownloadProgressChanged" />
<param name="onSourceDownloadComplete" value="onSourceDownloadComplete" />
<a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
</a>
</object> |
Nun folgt der etwas mühsame Teil: Sämtliche Logik muss in profanem JavaScript wie zu Silverlight 1 Zeiten verfasst und in das HTML-Dokument integriert werden.
1
2
3
4
5
6
7
8
| function onSourceDownloadProgressChanged(sender, eventArgs) {
var percentage = eventArgs.progress;
// your code here
}
function onSourceDownloadComplete(sender, eventArgs) {
// your code here
} |
Den Rest erledigt das Silverlight PlugIn dann aber von alleine.
English: The following article describes the ActionScript 3 metadata framefactory and its usage for creating a preloader.
Deutsch: Zahlreiche Wege führen zu einer Flash-Anwendung. Und der Weg über reinen Code ganz ohne Zeitleiste erfreut sich dabei zunehmender Beliebtheit – zumal mit dem Flash Development Toolkit (FDT) und dem Flex Builder zwei Eclipse basierte Entwicklungsumgebungen bereitstehen, die dem im Flash enthaltenen Editor Lichtjahre voraus sind. Doch diese Herangehensweise hat auch ein paar Tücken. Eine davon ist der Preloader, der bei größeren Anwendungen den Ladeprozess ansprechend visualisiert.
In klassischen Flash-Anwendungen wird vielfach die Zeitleiste für den Preloader missbraucht, indem am Anfang die Wiedergabe stoppt, bis der restliche Inhalt geladen ist – dafür muss natürlich sichergestellt sein, dass so viel Inhalt wie möglich erst in den späteren Bereichen der SWF-Datei liegt (was sich übrigens gut mit dem Bandbreiten-Profiler in Flash prüfen lässt). So ganz ohne Zeitleiste klappt das mit FDT oder dem Flex Builder natürlich erst einmal nicht. Doch ein Blick in das Flex Framework zeigt, dass dort eine Lösung namens Framefactory exisitert. Denn das Metadata [Frame(factoryClass=”Class”)] erlaubt es, Code explizit an den Anfang der SWF-Datei zu legen und diesen z. B. für einen Preloader zu nutzen, bevor der restliche davon unabhängige Inhalt geladen wird.
1
2
3
4
5
6
7
| package {
import flash.display.MovieClip;
[Frame(factoryClass="biz.wolter.app.manager.SystemManager")]
[SWF(width="800", height="600", frameRate="24", backgroundColor="#999999", pageTitle="My Rich Application")]
public class Application extends MovieClip {
}
} |
Die in der Framefactory referenzierte Klasse (hier analog zu Flex der SystemManager) enthält nun allen Code für den Preloader und die Initialisierung der Anwendung. Letzteres darf aber nicht durch eine „konkrete“ Referenzierung erfolgen, da ja dann der zugehörige Code mit dem SystemManager an den Anfang der SWF-Datei gepackt würde. Deshalb kommt hier nach einem erfolgreichen Ladevorgang die Methode getDefinitionByName zum Einsatz.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| package biz.wolter.app.manager {
import biz.wolter.app.controls.Preloader;
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.getDefinitionByName;
public class SystemManager extends MovieClip {
public function SystemManager() {
stop();
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
// Custom Preloader
Preloader.show();
}
/*
* Handle the loading progress
*/
public function onEnterFrame(event:Event):void {
if(framesLoaded == totalFrames) {
stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
Preloader.hide();
nextFrame();
create();
} else {
// nothing, cause Preloader handles itself
}
}
/*
* Finally create the application
*/
private function create():void {
var mainClass:Class = Class(getDefinitionByName("Application"));
var app:Object = new mainClass();
addChildAt(app as DisplayObject,0);
}
}
} |
English: The following article describes how you can quickly detect the usage of systemfonts or embedded fonts in AIR, Flash or Flex without the need of analysing the whole sourcecode.
Deutsch: Texte werden in Rich Applications (z. B. mit AIR, Flash oder Flex) normalerweise entweder mit Systemschriften oder durch eingebettete Schriften systemunabhängig dargestellt. Beide Varianten haben Ihre Vor- und Nachteile beispielsweise hinsichtlich Darstellungsqualität und Dateigröße. Mit bloßem Auge ist in einer fertigen Anwendung jedoch leider kaum erkennbar, um welche Variante es sich handelt. Und die Suche im Quellcode gestaltet sich oft wie die Suche nach der Nadel im Heuhaufen – gerade bei modularen Anwendungen, bei denen nachträglich geladene Inhalte auf Schriftkonturen der Hauptanwendung zurückgreifen sollten. Glücklicherweise gibt es jedoch einen kleinen Trick, der die Suche erleichtert. Denn ein weiterer wesentlicher Unterschied zwischen Systemschriften und eingebetteten Schriften ist, dass sich Systemschriften nicht transformieren lassen. Es reicht bereits aus, den betreffenden Inhalt (der Einfachheit halber am besten gleich die ganze Anwendung) minimal zu drehen (rotation) und schon werden Systemschriften nicht mehr dargestellt. Dies kann man sich somit zu Nutze machen, um bei einer vorhandenen Anwendung schnell zu erkennen, wo es sich um Systemschriften oder eingebettete Schriften handelt.
Am 12. September findet in der Börse Wuppertal die Konferenz NRW 08 statt. Veranstaltet wird das Ganze unter anderem von Daniel Fischer. Daniel ist nicht nur für sein Fachwissen rund um WCF (Windows Communication Foundation) sondern auch als Leiter der .NET-Entwickler-User-Group Niederrhein und als Vorstand der JustCommunity e. V. bekannt. Es freut mich sehr, dass ich auf der Nachfolgeveranstaltung des erfolgreichen “.NET Summit NRW” einem Vortrag zum Thema Rich Applications halten darf. Der Schwerpunkt liegt dabei auf dem “Designer und Developer Workflow” mit Adobe Flash und Flex. Aber auch eine Abgrenzung zu Silverlight darf in diesem Umfeld natürlich nicht fehlen. Über Vorschläge zum Inhalt und Themenwünsche im Vorfeld freue ich mich wie immer sehr…
Keine Frage, dass es bei großen Projekten nicht empfehlenswert ist, Code und Design zu vermischen. Doch in der Praxis macht gerade diese Vorgehensweise bei kleineren Projekten Sinn, da so die Erstellung
- relativ einfach erlernt und
- alles von einer Person in
- einem Werkzeug umgesetzte werden kann.
Viele Sprachen wie HTML und Co. erlauben die Verknüpfung von Logik und Oberflächenbeschreibung in einer Datei. Ein gutes Beispiel für den Erfolg und die Gefahren dieser Vorgehensweise ist Flash. Denn Flash erfreut sich gerade dank dieser Vermischung einer recht steilen Lernkurve und erlaubt es auch Programm(ier)novizen, schnell zu Ergebnissen zu kommen. Doch wer hier nicht mit Disziplin vorgeht, findet seine Codeblöcke bei Problemen nur schwer in den zahlreichen Zeitleisten und Objekten wieder.
Softwarearchitekten wird es freuen, dass dieses Vorgehen in Silverlight nicht möglich ist und eine klare Trennung von Code und Design erzwungen wird. Denn Silverlight nutzt anstelle von Code-Inside Code-Behind. D. h. die Logik (z. B. C#) wird nicht mit der Oberflächenbeschreibung (XAML) vermischt sondern in eigenen Klassen platziert (partial classes) – anders als übrigens in WPF mit dem eigens dafür vorhandenen code Tag:
1
2
3
4
5
6
7
8
9
| <Canvas xmlns...>
<Button Name="button1" Click="Clicked">Click Me!</Button>
<x:Code><![CDATA[
void Clicked(object sender, RoutedEventArgs e)
{
button1.Content = "Hello World";
}
]]></x:Code>
</Canvas> |
So schön das in der Theorie klingt, führt diese Aufteilung in der Praxis zu einer flacheren Lernkurve und Erschwert die Erstellung durch eine Person mit einem Werkzeug. Nur wer sowohl Expression Blend für das Design als auch Visual Studio für den Code sein eigen nennt und zusätzlich auch beherrscht, kommt in annehmbarer Zeit ohne weitere Unterstützung zu guten Ergebnissen.
Doch Abhilfe sollte in Silverlight möglich sein. Die Unterstützung von dynamischen Sprachen ließe sich kombiniert mit einer entsprechenden Erweiterung in XAML durchaus dazu nutzen, sollte Microsoft nicht selber nachbessern (wie gesagt, in WPF ist das ja bereits enthalten). Diese XAML-Erweiterung müsste nur den mit ihr verbundenen dynamischen Code interpretieren und ausführen. Bereits vorhanden bzw. angekündigt sind Codebibliotheken für Iron Ruby, Iron Python, Visual Basic Script und JavaScript. Einzig die Integration in XAML fehlt noch.