Böser Dispatcher

An dieser Stelle eines der vielen Gotchas bei .Net-Entwicklung.

Es gibt manchmal Klassen (oft ViewModel), die haben prim​är mal keine GUI-Referenz, werden aber manchmal wecheslweise in einem Worker-Thread ausgeführt. Problematisch wird dann eine eventuell daran gebundene GUI. Oder man muss einfach nur unterscheiden, ob man im Worker-Thread oder im GUI-Thread lebt.

Der Dispatcher ist mehr oder weniger das unterscheidbare Merkmal, an dem ein GUI-Thread von anderen unterschieden werden kann:

Gleicher Thread wie der Dispatcher… Gut, möchte man meinen. Doch diese Prüfung hat einen bösen Fehler.CurrentDispatcher hat Seiteneffekte: Existiert kein Dispatcher zum aktuellen Thread, wird ein neuer erzeugt. Dispatcher sind nämlich keineswegs GUI-Spezifisch, sondern ein allgmeiner Dispatch-Mechanismus. Der Name ist irreführend.

Korrekt ist dagegen die Prüfung mit diesem Idiom:

Doch leider zu kurz gedacht. Im Prinzip ist das Richtig. Doch nur so lange, als keiner das erstere Idiom mit Dispatcher.CurrentDispatcher verwendet hat und uns somit einen parasitären Dispatcher auf den Worker-Thread gesetzt hat. Irgendwann hat dann jeder Worker-Thread einen Dispatcher.

Also was tun? Gleich auf Application zugreifen … tja leider. Denn Applicaiton ist der einzig gute Ankerpunkt in diesem Fall.

Dabei soll aber nicht unerwähnt bleiben, dass es in einer GUI-Applikation durchaus mehrere UI-Threads geben kann. Typischerweise dann in mehreren Fenstern. Es ist unwahrscheinlich, aber es geht und dann wäre auch dieser Code hier wahrscheinlich inkorrekt.

Bei WinXP-Fotoanzeige Diashow-Intervall einstellen

Womit man auf seine alten Tage noch so zu tun bekommt. Windows XP glaubte ich ja eigentlich schon hinter mich gebracht zu haben. Doch da gibt es Leute, die es tatsächlich noch einsetzen. Es war ja auch nicht so schlecht… nur ein wenig unsicher sonst aber…

Und wer es einsetzt um damit Urlaubsfotos durchzublättern kommt auf die Diashow der Fotoanzeige. Da die Zeitintervalle zwischen den Bildern mit 3 sek nicht allen Leuten taugen, kommen dann Fragen, wie man dieses Intervall wohl ändert. Da es keine Oberfläche dafür gibt, bleibt nur die Registrierung zu bearbeiten. Konkret muss man unter HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionExplorerShellImageView gehen und dort den DWORD-Wert Timeout erstellen. Hinein kommt die Zeit in Millisekunden, die die Fotoanzeige zwischen zwei Bildern warten soll.

Aus gegebenem Anlass habe ich für diese einfache Aufgabe ein Programm geschrieben. Verwendet habe ich dazu WinForms und C#. Man wird also das .Net Framework 2.0 benötigen. Das Programm bietet eine simple Oberfläche um genau diese Eine Aufgabe zu erledigen. Gut für Leute, die häufiger mal die Zeitabstände ändern müssen, mit der Registrierung aber nix am Hut haben.

Download Programmdatei

Download Quellcode

Anmerkung: Das Programm ist nach dem QnD-Prinzip entstanden. Daher nur schnell zackzack entstanden… einfach so.

WPF Dependency Properties von innen Setzen

Entwicklung eines WPF-Composite-Controls mit Dependency Properties (aka. Abhängkgeitseigenschaften)

Ab und zu muss man bei der Etnwicklung von WPF-Oberflächen neue Controls erstellen. Nun gibt es verschiedene Arten von Controls. Man unterscheided sog. Lookless Controls und Composite Controls. Erstere sind quasi rein nur eine von UIElement abgeleitete Datenstruktur. Das gesamte Verhalten, das Aussehen und die modifikation der Datenfelder (die Dependency Properties) geschieht über Styles und dort wiederum mit Triggern und Binungen. Darum soll es hier aber nicht gehen. Hier geht es um die andere Art von Control: Um Kompositum-Kontrollelemente bzw. User-Controls. Also in Etwa ein Panel oder ein Window. Mehrere Controls sind in einem neuen Control zusammengepfärcht und interagieren intern miteinander, während sie nach außen hin wie ein einziges auftreten. Dies lässt sich mit und ohne View-Model machen. Man hat also die Wahl zwischen MVVM und code behind. Je nach komplexität des Kontrollements ist es entweder sinnvoll oder einfach Overhead, ein View-Model dazu zu bauen. Hier soll es jetzt um ein einfaches Control gehen und daher greifen wir auf code behind zurück.

Das Control

Entwickelt wird ein Datei-Auswahl-Control. Es besteht aus einem Label und einem Button. Klickt man den Button, so erscheint ein Datei-Öffnen-Dialog und die fürderhin ausgewählte Datei wird angezeigt. Gleichzeitig hat auch die extern sichtbare Eigenschaft „FileName“ ihren Wert geändert und alle Bindungen  darauf ändern sich mit. Die Wahl fällt auf ein Control mit Code-Behind. Somit können wir einfach auf das Click-Ereignis des Buttons reagieren. Dort muss dan aktiv der Wert der Eigenschaft geändert werden. Tatsächlich ist hier par Bindung das Control sein eigenes View-Model.
Bestandteile:

Vorgehen

Zunächst benötigen wir ein Control.
Daher legen wir eine XAML-Datei an und passend dazu eine Code-Behind-Datei. Wir erben von System.Windows.Control.

 

und

 

Controlaufbau

Das Control besteht aus zwei weiteren Controls: Button und Label. Wir fügen beide ein und Binden das Label an die noch zu erstellende Eigenschaft FileName. Damit das nacher funktioniert, muss die Source noch korrekt sein. Wir erreichen das recht einfach, indem wir dem Conttol(!) den DataContext setzen und auf sich selbs verweisen lassen. Das Control ist
so gesehen sein eigenes View-Model.

 

Abhängigkeitseigenschaften

Zur erfolgreichen Bindung benötigt das Control noch eine Dependency Property FileName:

mah beachte, wie per FrameworPropertyMetadata ein Standardwert mitgegeben wurde und die Bindungsoptionen standardmäßgig auf TwoWay definiert wurden. Dies hat im Folgenden den Vorteil, dass man von Extern (bei Verwendung) nicht bei Binungen Mode=TwoWay angeben muss.

Events

Wir wollten es einfacher mit dem Button. Nun fehlt noch der Eventhandler:

Man beachte hier die beiden Aufrufe der von DependencyObject stammenden Methodena: SetCurrenValue und ClearValue. Damit wird der Wert bzw. die Bindung hinter einem Dependency-Property geänder bzw. auf den Std.-Wert (aus den Metadaten) zurückgesetztgesetzt. Verwendet man vergleichsweise dazu GetValue/SetValue wie in der Implementierung des CLR-Properties, zerstört man die Bindung. Das wäre fatal, da dann die Funktionalität zusammenbricht. An dieser Stelle sein noch kurz auf die Doku verwiesen… Demnach seien CLR-Getter/Setter nur so zu implementieren, wie hier gezeigt. Nur Aufrufe von GetValue/SetValue und keine weiteren Aktionen nebenher. Denn WPF ruft gerne selbst GetValue/SetValue mit passenden Parametern auf und umgeht dabei die CLR-Properties. Zusatzaktionen
muss man daher in passenden PropertyChanged– bzw. CoerceValue– oder ValidateValue-Callbacks machen. Auf selbige wurde hier verzichtet.

Eingebaut

Nun sehen wir uns noch an, wie dieses Control zu verwenden ist. Dazu wurde ein WPF-Fenster gestaltet, dass dieses Control verwendet und gleichzeitig einen Textblock an unsere neue Dependency-Property bindet:

 

… es ist kein Code-Behind nötig….
Man beachte, wie zunächst der text „aus window“ im Control steht, und später der Wert aus dem Eventhandler des Controls (siehe im Code: cancel oder OK-Zweig).

Programmiersprachen und Metadaten

Schaut man sich heute mal so den Quelltext eines mittleren Programms an, welches in C, C++ oder ähnlich geschrieben ist, wird man feststellen, dass es von Metadaten und Stringlisten nur so wimmelt. Der Grund ist klar die komplexität des Programms. Verursacht durch die Anforderungen die nach Flexibilität verlangen. Vereinfacht gesagt reicht eine Enumeration als Typ nicht mehr aus – stattdessen wird zusätzlich oder ersatzweise eine Liste oder ein Feld mit Zeichenketten und oder Konstanten angelegt. Oder es werden zusätzliche Elementvariablen in Klassen oder Strukturen eingeführt, die Metadaten zu ihren Objekten halten oder oder oder.

Sieht man sich dagegen ein Programm in einer verwalteten Sprache an wie Java oder .Net, stellt man ähnliches fest aber weit weniger. Meist sind die Programme komplexer geworden, weil nun mehr Freiheiten bestehen. Aber eigentlich benötigen sie derartiger Hilfskonstruktionen weniger. Stattdessen wird Reflexion häufiger eingesetzt. Typen (z.B. eine Enumeration) werden einfach definiert und verwendet (klassisch, Lehrbuch) und wenn die Anforderungen komplexer werden, werden diese Typen reflektiert. Man verlässt sich auf die von der Laufzeitumgebung bereitgestellten Metadaten und inspiziert sie / verwendet sie passend.

Das Resumé aus dem Ganzen ist nun: Früher, in den kompilierten Sprachen gab es wenig bis keine Metadaten. Ergo führen viele Programme im Quelltext welche ein (die aber nur eher schlecht mit den eigentlichen Daten (Kode) integrieren). Man stellte also fest, dass quasi jedes etwas komplexere Programm solche Metadaten benötigt. In der Folge berücksichtigte man das bei der Entwicklung von verwalteten Sprachen und sagte sich: Lass uns gleich für alle Typen zwangsweise Metadaten einführen und mitschleppen. So ist es bei Java, C# und .Net also möglich, Reflexion zu verwenden und Daten über Typen zu ermitteln. Überdies erlauben beide Sprachen das Anfügen von zusätzlichen Metadaten in Form von Attributen bzw. Annotationen. Das hat letztlich zu einem neuen Stil in der Entwicklung geführt. Man verlässt sich nun mehr auf Metadaten im Typsystem und legt Dinge generischer aus. Zwar werden Programme dadurch langsamer aber auch flexibler, stabiler und besser wartbar.

Über die Möglichkeit, die das Generieren neuer Typen zur Laufzeit angeht, lasse ich mich ein andermal aus.