Silverlight und WPF Bindings – leicht missbraucht?

Manchmal ist es doch überraschend, an welchen Stellen Bindings verwendet werden können. So handelt es sich bei der Width Eigenschaft einer ColumnDefinition im Grid um eine DependencyProperty, die man dynamisch binden kann. Mit ganz witzigen Effekten, wie ich nun beschreiben möchte – hier eine schnelle Lösung, elegant wird es erst bei Einsatz von ValueConvertern.

In einem privaten Projekt werden zu einer Buslinie die Haltestellen und deren Abstand eingegeben. Ich wollte nun so einen so schönen Zeitstrahl haben, wie man ihn hier in der Gegend auf den ausgegängten Busfahrplänen findet.

Zeitstrahl

Im Programm sind bereits die Haltestelle als Objekte (Knotenpunkt) vorhanden, die INotifyPropertyChanged implementieren. Eine dieser Eigenschaften ist die Fahrzeit zwischen zwei Haltestellen in Minuten. Ich habe nun eine neue Eigenschaft der Art GridLength hinzugefügt – wie gesagt, ein ValueConverter würde eine sauberere Trennung der Softwareschichten bedeuten. Diese Eigenschaft meldet entweder als Breite 0 Pixel (wenn die Fahrzeit 0 ist) oder die (positive) Fahrzeit mit dem GridUnitType.Star – entsprechend der XAML Texteingabe 1*, 2*, 3* etc.

Ein UserControl (FahrplanAnzeigen) wird nun an eine Liste von Haltestellen gebunden – die Liste selbst wird nur sehr faul überwacht und Änderungen führen zu einem vollständigen Neuaufbau: in einem echten Stück Software würde man das sicher optimieren. Für jede Haltestelle wird eine ColumnDefinition erzeugt und die beschrieben Eigenschaft über die BindingOperations an die Width gebunden.

Silverlight sorgt nun mit ein bisschen XAML Definition automatisch dafür, dass die Haltepunkte proportional über den Zeitstrahl verteilt werden. Reaktionen bei Änderung der Größe sind nicht notwendig. Mehr noch: ändert man die Fahrzeit eines Haltepunktes im Formular, so passt sich der Zeitstrahl über das Binding ohne irgendwelche weitere Interaktion des Programms an. Das sieht schon recht witzig aus – vor allem für ein geschenktes Feature.

Happy Coding

Jochen

Silverlight 5 vs. ANSI (Windows-1252) Encoding

Für eine kleine Auftragsarbeit im Familienkreis will ich mit Silverlight 5 eine XML Datei lesen und schreiben – als Ersatz für den Schedule Wizzard des Bus Simulator 2012 Spiels, der unter Windows XP nicht richtig funktioniert. Wenn man allerdings versucht, eine lokale Datenstrom in ein XDocument zu laden oder ein solches zu schreiben, so gibt es eine kleine Überraschung: von Hause aus unterstützt Silverlight das Windows Encoding und esp. die 8-Bit Windows Codepage 1252 nicht.

Tatsächlich sind die hier verwendeten Dateien genau betrachtet auch unzulässig, allerdings drücke ich doch allzu gerne beide Auge zu, da ich selbst schon oft in diese Falle gelaufen bin. Hier werden XML Dateien verwendet, in deren ?xml Instruktion kein Encoding angegeben ist, die aber tatsächlich in der 8-Bit Codepage 1252 von Windows verfasst sind. Das heißt zum Beispiel, dass das €uro Symbol mit dem Wert 128 hinterlegt ist – entsprechend auch die Umlaute. Silverlight wird eine solche Datei mit 1252er Umlauten erst gar nicht laden und beim Speichern das UTF-8 Format verwenden – inklusive einem korrekten Encoding in der ?xml Instruktion. Damit kommt aber das Spiel nicht zurrecht.

Ich habe ohne langes Suchen eine kleine eigene Implementierung verwendet, die ich hier kurz vorstellen will – recht trivial und meiner Ansicht nach dem Zweck angemessen. Die Implementierung selbst findet man in diesem Archiv.

Erst einmal habe ich mir (mit Hilfe vom richtigen .NET und dem Encoding.GetEncoding(1252)) eine Abbildungsvorschrift zwischen Windows 1252 Bytes und 16-Bit UNICODE Zeichen erstellt und diese in Silverlight eingebunden (man siehe hierzu Fahrplan.cs im Archiv). Beim Laden wird die gesamte Datei (die für die konkrete Anwendung extrem klein ist) binär als byte-Feld unverändert eingelesen. Mit Hilfe der Abbildungsvorschrift wird pro byte das zugehörige UNICODE Zeichen als char erstellt, i.e. 128 gibt € und so weiter. Dieses char-Feld bildet dann eine Zeichenkette via new string(feld) und über die System.IO.StringReader Klasse kann das XDocument klaglos erstellt werden.

Das Speichern ist ein wenig trickreicher. Hier wird das XDocument erst einmal im Speicher mit Hilfe einer MemoryStream Instanz gespeichert. Der Einsatz von XmlWriter und XmlWriterSettings erlaubt es dabei, das Encoding auf Encoding.Unicode zu fixieren. Die UNICODE char Zeichen im Speicher werden nun alle über die Abbildungsvorschrift in Windows 1252 Bytes umgesetzt – ist dies nicht möglich, wird ein ? als Ersetzungszeichen verwendet. Der erste char wird dabei ignoriert, hier würde in der Datei die BOM (Byte-Order-Mark) stehen, die eine Identifikation des Dateiinhaltes als UNICODE ermöglichen soll. Somit wird aus einem ursprünglichen UNICODE char-Feld einfach ein byte-Feld in Windows 1252 Codierung, das dann binär in eine lokale Datei gespeichert wird. Aber Vorsicht: hier ist in der ?xml Instruktion immer noch das Encoding als UTF-16 festgelegt, was zumindest von der Originalformatierung abweicht. Im Programmcode werden die entsprechenden Bytes beim Schreiben der Datei entfernt.

Etwas ekelig, aber nicht so schlimm, wie es sich anhört. Der eigentliche Code zum Lesen und Schreiben sind wenige Zeile und die lange Abbildungsvorschrift kann man sich leicht automatisiert erstellen. Besser als ein eigenes Encoding, oder?

Soweit zum Thema: Was Sie eigentlich nie über Silverlight wissen wollten aber gezwungen waren sich damit auseinander zu setzen 🙂

Jochen

Kinderkram

Mal wieder ein kleines Intermezzo. Die Frage meines Sohnes “Papa, kannst Du nicht ein Jump&Run programmieren?” konnte ich natürlich 🙂 nicht einfach so im Raum stehen lassen. Da ich mich eh weiterhin in Silverlight einarbeiten wollte, habe ich mich entschieden, mal einen Prototyp zu erstellen. Viel kann er zwar nicht, aber so mit einer Spielfigur rumlaufen, Dinge einsammeln etc. funktioniert schon. Der Code für diese erste Variante ist schon fertig (auch öffentlich über das Hilfedokument verfügbar, man siehe darin den Link ganz unten), an den optischen und aktustischen Effekten arbeiten wir noch – so kann die Spielfigur beim Laufen auch animiert werden, dazu muss man aber Bildsequenzen erstellen, was recht lästig ist.

Den aktuellen Stand möchte ich dem geneigten Leser aber nicht vorenthalten.

Have Fun

Jochen

ListBox, ComboBox oder was?

Im Rahmen meiner Einarbeitung in Silverlight / WPF bin ich auf eine Idee gestossen, die ich einmal an einem rudimentären Beispiel als Anschauungsmaterial implementiert habe. Die Aufgabenstellung an sich ist eigentlich sehr einfach: aus einer begrenzten Liste von Auswahlelementen soll eines vom Anwender ausgewählt werden. Ganz klar die Aufgabe einer ComboBox. Die Auswahl soll zudem graphisch und nicht in Textform präsentiert werden – auch keinerlei Herausforderung für Silverlight / WPF. Wie das Beispiel zeigt, kann man sich das auch optisch ein wenig anders vorstellen – zu den einzelnen Elementen der Testseite gleich mehr.

Startzustand

Im initialen Zustand wird die Auswahlliste als ListBox dargestellt – ohne die typische Sondervisualisierung der ComboBox mit dem Auswahlfeld zum Aufklappen. Verändert sich die Auswahl, so übernimmt die Listbox die Anzeige – auf Aspekte des ausgewählten Eintrags kann im XAML wie gewohnt referenziert werden, wie das Bild links oben und der relative Pfad des Bildes daneben zeigt. Das ist nun wirklich nichts Besonderes bis hierhin.

Aufgeklappt

Die Besonderheit zeigt sich aber, wenn man die Auswahl bestätigt. Die ListBox klappt dann scheinbar zu und zeigt nun nur noch den ausgewählten Eintrag.

Zugeklappt

Das Beispiel kann man sich selbst einmal hier anschauen, die Quellen gibt es hier. Es handelt sich wirklich nur um eine sehr elementare Implementierung, sicher nicht um ein vollwertiges Control. Was tut das Beispiel jetzt schon:

  • Beim Starten ist einer der drei Alternativen ausgewählt – sieht im Beispiel etwas häßlich aus, da meine Beispielbilder einen teilweise transparenten Hintergrund haben und die Auswahleinfärbung der Listbox auch im zugeklappten Modus erscheint: einfach vorstellen, dass der Hintergrund der Visualisierungselemente nicht transparent ist (man kann irgendein FrameworkElement verwenden).
  • In der oberen Zeile wird die Auswahl zur Demonstration als Bild und Pfad zusätzlich angezeigt.
  • Ein einfacher Klick auf die gewählte Alternative (großes Bild) öffnet die Auswahlliste.
  • Die Navigation in der Liste mit Maus oder Tastatur verändert die Auswahl, insbesondere kann diese wie gewohnt mit Strg-Click aufgehoben werden.
  • Ein Doppelklick oder die Taste ENTER beendet die Auswahl und schließt die Liste, es wird nun die letzte Auswahl angezeigt.
  • Die Eingabe des Pfades in der oberen Zeile kann zur Änderung der Auswahl verwendet werden – uh, Injection Attack möglich, schert hier aber nicht.
  • Hat die zugeklappte Liste den Fokus, so kann die Auswahl weiterhin mit der Maus verändert werden – die Liste klappt dazu automatisch auf.
  • Im XAML der Seite sieht man, dass die Auswahl vorbelegt werden kann, was natürlich optional ist.

Happy Coding

Jochen

Mal was ganz anderes – Zeitreise…

Mein Sohn hat hier zwei LEGO Spybotics herumstehen, eine Abart der ersten Mindstorms Generation. Im Internet gibt es zwar ein paar gute Seiten dazu, aber im Wesentlichen ist die Zeit definitv vorbei (ich schätze mal so seit deutlich über 5 Jahren). Wie dem auch sei: zum Herumspielen, Lernen und vielleicht Einstieg in die Programmierung (von Robotern und Allgemein) ganz gut.

Ich habe mir daher mal einige Unterlagen zusammen gesucht (vor allem über diesen Einstieg) sowie das alte Mindstorms SDK von Lego installiert. Da ich aber immer auch daran interessiert bin, die Dinge hinter der Fassade zu verstehen, habe ich auf Basis der LASM Dokumentation begonnen, einen Disassembler für Spybotics Programme zu schreiben. Dieser erlaubt es, das aktuelle Programm (die aktuelle Mission) im dem Spybotic anzuschauen (egal, ob eine der vorderfinierten Missionen, eine mit der beliegenden Software erstellen Mission oder ein völlig eigenständiges Programm, das man etwa mit BrickCC zusammengestellt hat). Das sieht dann etwa so aus (hier eigene Spielereien):

spy1.jpg

Das Programm ist alles andere als fertig und hängt sich am und an und vor allem beim Beenden auch mal auf (ich glaube aber, dass die Ursache dabei die COM Schnittstellenbibliothek ist, die mit dem SDK kommt). Aber wen’s interessiert, hier ein Setup für Windows (ich habe es unter Vista eingesetzt). Man braucht natürlich mindestens einen Spybotic am besten mit funktionierender Originalanwendung (inklusive dem seriellen Anschluss), die COM Schnittstellenbibliothek aus dem SDK (am besten einfach das ganze SDK installieren) und Microsoft .NET 4.0 (Client Profile). Die Installation enthält auch die Quelltexte auf Basis von Visual Studio 2010, alle Quellen sind (wie von dieser Seite vermutlich schon gewohnt) in C#. Benutzung selbstverständlich völlig ohne Gewähr…

Bin ja mal gespannt, ob noch jemand an so altem Kram interessiert ist…

Jochen