Gemeinsame Icon-Bibliothek in größeren Desktop-Apps

IconJe umfangreicher Desktop-Apps werden, desto größer wird auch ein Problem, welches zumeist zu Beginn der Entwicklung unterschätzt wird: Wo werden Icons abgelegt, welche von verschiedenen Programmteilen verwendet werden? Viele verschiedene Programmteile und Module (und wie sie auch immer genannt werden…), bei denen jeweils lokal Icons abgelegt werden, können nach einigen Jahren stetiger Entwicklung für Chaos sorgen. Bei meinen Projekten verstärkt sich das Problem zusätzlich aufgrund der Tatsache, dass sich ältere Windows.Forms- und neuere WPF-Komponenten mischen.

Bezogen auf WPF könnte man jetzt (zu Recht) sagen, die Packet URIs [1] lösen dieses Problem für WPF-Basierte Anwendungen bereits. Sie ermöglichen es nämlich, Icons in einer gemeinsam genutzten Assembly abzulegen und von anderen Assemblies direkt aus dem Xaml-Code heraus darauf zu referenzieren. Aber ganz ehrlich: Ich persönlich bin absolut kein Fan der Syntax dahinter, da erstens teils sehr lange URI Pfade herauskommen und zweitens keine direkte Intelli Sense dafür zur Verfügung steht. Dazu kommt, warum auch immer, dass ich die Syntax stets nach einigen Tagen oder Wochen wieder vergessen habe. Gehen wir zum Beispiel von einer Assembly „CommonAssembly“ aus, welche alle gemeinsam verwendeten Icons für ein größeres Projekt enthalten soll. Abhängig der darin umgesetzten Ordnerstruktur käme etwa nachfolgende Packet URI raus.

Meine aktuelle Alternative für dieses Problem ist es, über eine eigene MarkupExtension zu gehen. Diese MarkupExtension nimmt eine Enum als Parameter, welche jedes verfügbare Icon als Member hat. Diese Enum hat den Vorteil, dass innerhalb des Xaml-Codes Intelli Sense Unterstützung zur Verfügung steht. Das Ergebnis (also das Icon) kann man sich auch direkt im Designer anschauen, da MarkupExtensions innerhalb des Designers von Visual Studio direkt ausgeführt werden. Nachfolgend ein Beispiel aus dem ModelViewer von Seeing# [2]. Hier wird bei den ToggleButtons jeweils ein Icon über die Content-Eigenschaft zugewiesen. Die MarkupExtension heißt hier „ModelViewerIcon“, der Parameter mit der Enum einfach „Icon“. Zusätzlich gibt es hier noch den Parameter „ResultType“. Grund dafür ist die Tatsache, dass an manchen Stellen das Icon als Typ „Image“ zugewiesen werden muss und an anderen als Type „ImageSource“. Ob noch weitere Typen dazu kommen, weiß ich derzeit noch nicht – ich lass mich mal überraschen.

Aktuell ist es im ModelViewer noch so implementiert, dass sich die MarkupExtension direkt im gleichen Projekt befindet. Generell kann sich diese aber genauso in einer anderen Assembly befinden – ganz wie bei jeder anderen MarkupExtension auch. Nachfolgend noch das Coding der MarkupExtension und der Enum, um sich ein detailliertes Bild davon zu machen.

Die Umsetzung ist, wie man sieht, relativ einfach gestaltet. In der Methode „ProvideValue“ wird das Packet URI mit dem gewünschten Icon zusammengebaut. In diesem Beispiel gehe ich der Einfachheit halber davon aus, dass es einen Ordner mit allen zur Verfügung stehenden Icons gibt. Wird die Zahl der Icons so groß, dass dieses Vorgehen unübersichtlich wird (was ja schnell passiert), wäre es ein guter Weg, mit der Unterteilung in Unterordner auch verschiedene MarkupExtensions zu entwickeln. Somit geht der Vorteil der Unterstützung der Intelli Sense nicht verloren. Auch verschiedene MarkupExtensions verteilt auf verschiedene Assemblies sind denkbar, um so je nach Komponente bzw. Zugehörigkeit zu einer Schicht andere Icons anzubieten.

Ein Nachteil dieser Lösung ist natürlich noch, dass Windows.Forms-Anwendung noch nicht berücksichtigt sind. Mein persönliches Ziel ist aber, auch diese Welt auf dem gleichen Weg abzudecken, entweder über eine eigene Ableitung der ImageList-Klasse oder über eine eigene Component, welche sich um die Zuweisung der Icons zu Steuerelementen kümmert. Im schlimmsten Fall bliebe noch das Code Behind für diese Aufgabe übrig – letzten Endes kann aber eine gemeinsame Icon-Bibliothek benutzt werden und das ist für mich das wichtigste Ziel.

Verweise
[1] = https://msdn.microsoft.com/de-de/library/aa970069(v=vs.110).aspx
[2] = https://github.com/RolandKoenig/SeeingSharp/tree/master/Tools/SeeingSharpModelViewer

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.