Thomas Woelfers Baustatik Blog

Baustatik-Software und was sonst des Weges kommt

Zip ist Teil von XP

Ich sitze häufiger mal vor fremden Windows XP Rechnern und stelle dann immer wieder mal fest das dort WinZIP installiert ist - das irritiert mich immer wieder aufs neue, weil dadurch eine meiner Ansicht nach recht praktische Eigenschaft von XP außer Kraft gesetzt wird: Windows XP (und Windows 2003) kommt nämlich auch ganz ohne externe Programme wie WinZIP mit ZIP-Dateien klar - XP hat nämlich eine eingebaute Unterstüzung für .ZIP-Dateien.

Man kann dabei im Explorer einfach direkt in .ZIP-Dateien hineinnavigieren, oder Dateien rein- und rausziehen: Solche Dateien werden in XP mehr oder minder wie normale Ordner verwaltet. Aber eben nur dann, wenn man kein WinZIP installiert...

Um einen neuen ZIP-Order anzulegen klickt man einfach mit der rechten Maustaste in den Order in dem die Datei angelegt werden soll und wählt dann den passenden Befehl aus dem Objektmenü. Zeigt der Explorer gerade den Inhalt einer ZIP-Datei an, dann kann man auch im Datei-Menü des Explorers eine Passwort für diese Datei vergeben...

WinFX für alte Windows

Jetzt ist es raus: Microsoft löst die enge Kopplung zwischen WinFX und Longhorn. Resultat: Das WinFX Framework wird zwar mit der nächsten Windows-Version ausgeliefert werden, wird aber auch als separate Version für Windows XP und 2003 Server zur Verfügung stehen. Im besonderen gilt das für Avalon (Präsentation) und Indigo (Kommunikation) - man kann also nun WinFX als Entwicklungsplatform benutzen um Anwendungen für alle Windows-Versionen ab XP zu entwickeln. ( WinFX für Downlevel-Windows FAQ hier )

Wer sich jetzt über seine Investitionen in Windows.Forms ärgert - WinFX bietet ja nun auch im Client-Bereich eine Menge mehr als die aktuelle .Net Version - der kann beruhigt werden: Avalon und Windows.Forms sollen bidirektional kommunizieren können. Das habe ich noch nicht ausprobiert, werde das aber so bald als möglich tun - wir haben hier nämlich eine Menge Entwicklungszeit in Windows.Forms gesteckt ... :-)

Dazu muss ich aber ersteinmal zusammenpassende IDEs, Longhorn-Betas und SKDs aus der Sammlung an Beta-CDs zusammensuchen und installieren... ich denke mal das es irgendwann im September so weit sein wird. Sobald ich mehr dazu sagen kann werde ich das an dieser Stelle tun.

Nervige Massketten...

Im Stahlbau hätte man gern Vermassung in Millimetern, im Betonbau in Zentimetern... die Symbole der Massketten unterscheiden sich naürlich auch: Eigentlich kein großes Problem wenn man nur kurz eine Masskette zeichnen will.

Es wird allerdings ein wenig nervig wenn man wie wir beim Rahmenprogramm einige hundert unterschiedlicher Standardprofile (gar nicht zu reden von den frei definierbaren) hat - und für alle dann von Hand Symbole programmieren muss die die Vermassung auch bei dynamischen Veränderungen an den Abmessungen an die richtige Position malen.

Natürlich müssen auch für alle die Querschnittswerte ermittelt werden, und es muss natürlich auch überprüft werden ob die angegebenen Abmessungen (Radien, Blechdicken...) zulässig sind. Da kann man sich schon ein paar Tage mit beschäftigen - was wir in letzter Zeit auch getan haben.

Die alten Programme haben das ja schon immer - jetzt geht das auch fürs kommende Faltwerksprogramm. Das ist schön - aber Nerven kostet das trotzdem.

Windows XP SP2 auf deutsch

Hier ist die offizielle deutsche Seite zum Windows XP Service Pack2. Da gibts das Download einen Link zum 'neuen' Windows-Update und Texte und Dokumentationen rund um das Programm. Der Fokus der Seite liegt zwar auf Entwickler, aber auch sonst jedermann kann da natürlich das deutsche SP2 erhalten.

Die TreeView und die Bitmaps

Die Windows.Forms TreeView hat eine ImageList - und in dieser ImageList kann man die Bitmaps unterbringen, die für die einzelnen Nodes im Tree verwendet werden. Leider zeigt sich hier auch bei .Net das etwas merkwürdige Erbe von Win32: Die TreeView - beziehungsweise deren Nodes - haben nämlich zwei Felder, mit denen Bitmaps gesetzt werden können. Das eine ist der ImageIndex, das andere der SelectedImageIndex.

Der ImageIndex enthält den Index des Bildes aus der ImageList, das verwendet werden soll, wenn sich die Node im 'Normalen' Zustand befindet. Der 'SelectedImageIndex' ist der Index des Bildes für den ausgewählten Zustand einer Node. Ich kenne zwar kein Programm das im Baum ein anderes Icon für ausgewählte Nodes verwendet als für Nodes im Normalzustand - aber sei's drum, ist ja schon wenn man die Möglichkeit hat.

Nun würde man erwarten das es außerdem auch einen Index für den 'aufgeklappten' Zustand einer Node gibt: Im Baum ist das schließlich deutlich wichtiger als der 'ausgewählte' Zustand - darum verwendet man schließlich einen Baum.

Unnötig zu sagen: Das gibts natürlich nicht. Wenn man so etwa 'ungewöhnliches' machen will wie einen Baum bei dem man andere Icons im aufgeklappten und geschlossenen Zustand verwendet, dann muss man das von Hand machen. :-(

Dazu implementiert man einen Handler für AfterExpand() und AfterCollapse() - und darin setzt man dann in Abhängigkeit von der Node die Image-Indizes. Dabei wirds dann noch nerviger: Man muß nämlich sowohl den 'ImageIndex' als auch den SelectedImageIndex setzen - auch wenn man sich für den 'SelectedImageIndex' eigentlich gar nicht interessiert.

Bitmaps in VS.Net Projekten laden

Die Verarbeitung von Resourcen wie zum Beispiel Bitmaps zur Laufzeit von Programmen die Sie mit dem Visual Studio erstellen ist ein wenig merkwürdig - unverständlich sogar, würde ich sagen. Das ganze Modell erscheint ein unausgegoren... Trotzdem kann man natürlich Bitmaps laden.

So gehts:

Angenommen Sie haben ein Projekt in dem sich das Bitmap 'Bitmap1.bmp' befindet. Dieses Bitmap soll nun im Code geladen werden. Das geht im Prinzip so:

Bitmap bmp = new Bitmap( GetType(), "Bitmap1.bmp");

Der Type spezifiziert dabei die Assembly in der sich das Bitmap befindet. Mit anderen Worten: Man legt damit fest, das sich die Bitmap-Resource in der gleichen Assembly befindet wie 'Type'. Der String gibt einfach den Namen der Resource an.

Wenn man diesen Code übersetzt und ausführt bekommt man aber eine Exception... :(

Grund: Es reicht nicht die Bitmap ins Projekt aufzunehmen. Man muss auch (manuell, und zwar jedes mal wenn man ein neues Bitmap anlegt !) festlegen das das Bitmap tatsächlich mit ins Binary soll. Dazu muss man in den Properties der Bitmap die Eigenschaft 'BuildAction' von 'Content' auf 'Embedded Resource' stellen. Dann gehts.

Aber auch nur so lange sich der abgebildete Code in einer Klasse befindet, die sich selbst direkt im Default-Namespace des Projektes befindet. Ist außerdem noch ein Namenspace namens 'Test' vorhanden - liegt der Code also in der Klasse 'Form1' in 'DefaultNamespace.Test' - bekommt man wieder eine Exception.

Grund: Der zugrunde liegende Resource-Manager baut den Namen der gesuchten Resource aus der Assembly von 'Type' und aus dem Namespace von Type zusammen. Es wird dann also das Bitmap 'DefaultNamespace.Test.Bitmap1.bmp' gesucht - und das gibts nicht.

Lösung: Man muss das Bitmap im Projekt umbennen - und zwar in Test.Bitmap1.bmp.

Einfache aber beknackte Regel: Das Bitmap muss im Projekt mit einem Namen vorliegen, der den kompletten Pfad im Namespace des 'Types' bis aufs erste Element enthält.

Wer immer sich das ausgedacht hat sollte dafür bestraft werden. Ist natürlich nur meine Meinung...

Die ausführliche Statistik der Statiksoftware

Gestern habe ich die 'kurze' Statistik-Funktion des TimeServers beschriebén. Den TimeServer haben Sie dann (in Form eines kleinen roten D in der Taskleiste) auf dem Rechner laufen, wenn Sie unsere Baustatik-Programme im Work&Cash Verfahren nutzen.

Der TimeServer hat auch eine Befehl zum anzeigen einer ausführlichen Statistik. Nicht sonderlich überraschenderweise hat dieser Befehl den Namen 'Ausführliche Statistik anzeigen'.

Der Befehl öffnet einen Dialog mit zwei Listen. In der Liste 'Beteiligte Computer' erhalten Sie eine Aufschlüsselung wieviel Zeit die einzelnen mit dem TimeServer auf Ihrem Computer verbundenen anderen Computer verbraucht haben. Dabei werden Aenderungen bei Computernamen nicht mitgeführt: Wenn ein Rechner unter dem Namen 'Pauls Rechner' Zeit verbraucht hat und dann in 'Müllers Rechner' umbenannt wird, dann taucht er zweimal in der Liste auf.

In der Liste 'Verbrauchte Zeit' erhalten Sie eine Übersicht, wieviel Zeit an welchen Tagen verbraucht wurde: Damit können Sie sich einen Eindruck darüber verschaffen, wie hoch Ihr Zeitverbrauch eigentlich ist. (Kleiner Tipp: Die Kosten werden meist deutlich unterhalb der Telefongebühren liegen - es lohnt sich nicht wirklich, viel Zeit auf Analyse der Statistik zu verschwenden...)

Work&Cash Timeserver: Das bedeutet die Statistik

Wenn Sie unsere Statikprogramme mit einem Work&Cash Vertrag benutzen, dann läuft auf Ihrem Rechner das Timeserver Programm. Diese Programm besorgt die Buchhaltung für Ihren Work&Cash Vertrag. Wenn Sie mit der rechten Maustaste auf das rote 'D' Symbol in der Taskleiste klicken, dann erhalten Sie das TimeServer Objektmenü - die folgenden Blog-Einträge werden die dort zu findenden Befehle ein wenig erläutern. Heute gehts um den Befehl 'Aktuelle Statistik anzeigen'.

Der Befehl öffnet eine Dialogbox die in zwei Teile aufgeteilt ist. Der obere Teil ist grau hinterlegt, der untere weiss. Im oberen Bereich finden Sie die folgenden Angaben:

Zeitpunkt der Statistik: Das gibt den Zeitpunkt auf Ihrem Rechner an, an dem die angezeigten Daten Gültigkeit hatten.

Momentan verwendete Zeitblöcke: Ihre Arbeitszeit wird in 'Blöcken' verwaltet, wobei ein Block jeweils eine gewisse Menge an Arbeitszeit enthalten kann. Die 'Mege' an Zeit pro Block ist beliebig, und Blöcke können auch in kleinere Blöcke unterteilt werden. Diese Angabe hier sagt, wie viele Zeitblöcke momentan auf Ihrem Rechner verwendet werden.

Momentan zur Verfügung stehende Zeit: Die Anzeige gibt an, wieviel Arbeitszeit momentan auf Ihrem Rechner verfügbar ist. Die Angabe erfolgt sowohl in Studen als auch in Sekunden. Notgedrungen ist die Stunden-Angabe dabei gerundet.

Berechnete Zeit seit dem letzten Start: Gibt an, wieviel Arbeitszeit Sie seit dem letzten Start des TimeServers verbraucht haben. Zeit wird nur dann verbraucht, wenn auch ein Statikprogramm betrieben wird.

An der Berechnung beteiligte Computer: Gibt an, wieviele Computer (aus Ihrem LAN) Zeit von den Blöcken auf Ihrem Computer verbraucht haben. Wenn Ihr Rechner als Server für andere Rechner dient, dann steht hier eine Zahl größer als 1 - sonst eine 1.

An der Berechnung beteiligte Prozesse: Gibt an, wie viele unterschiedliche Sitzungen mit den einzelnen Statikprogrammen gezählt wurden. (Wenn Sie zum Beispiel das Tragwerksprogramm zweimal und das Plattenprogramm einmal starten, dann wird hier eine '3' angegeben.)

Anzahl momentan betrachteter Computer: Gibt an, wieviele Computer zum aktuellen Zeitpunkt mit dem TimeServer verbunden sind. Wenn Ihr System nicht als Server fungiert, dann steht hier immer eine '1'.

Im weissen Bereich erfolgt eine Auflistung aller Zeitblöcke die sich auf Ihrem System befinden: Blöcke deren Haltbarkeit abgelaufen ist, werden als 'abgelaufen/verschoben/leer' bezeichnet. Für jeden Block der noch gültige Arbeitszeit enthält, enthält die Liste eine Zeile mit der Angabe der im Block verfügbaren Stunden (und Sekunden).

Wie baut man ein Attribut in C#?

In .Net kann man Metadaten an Klassen und Methoden hängen um diese mit zusätzlichen Informationen auszustatten. Die Zuordnung dieser Metadaten zu einer Methode (oder Klasse...) erfolgt dabei über 'Attribute'.

Dabei gibt es eine ganze Menge von mitgelieferten Attributen mit denen man zum Beispiel erklärende Texte an Property-Accessors zuweisen kann: Diese Texte werden dann vom Property-Grid im 'Hilfe'-Bereich angezeigt. Man kann Attribute aber auch selbermachen - das ist sogar ganz einfach.

Angenommen man hat einen get/set Accessor mit dem man einen double-Wert einstellen kann:

double Groesse
{
   get{ return this.groesse; }
   set{ this.groesse = value; }
}

Nun will man den Accessor mit einem zulässigen Maximalwert ausstatten. Dafür gibt es kein mitgeliefertes Attribut, man möchte aber das die Sache hinterher ungefähr wie folgt aussieht:

[ MaximumValue( 400.0)]  // 400 soll der maximalwert sein
double Groesse
{
// ... 

Damit kann man nun an anderer Stelle im Quellcode (zum Beispiel auf der Dialogbox in der der Anwender den Wert angeben kann) nach einem MaximumValue Attribute suchen ( Type.Attributes ), und anhand dessen Wert überprüfen ob die angegebene Zahl OK ist. Stellt sich die Frage aus welchem Himmel das MaximumValue Attribut dann fällt....

Attribute selbermachen: So gehts

Eigentlich ist die Sache ganz einfach: Ein Attribut ist einfach eine Klasse die von System.Attribute abgeleitet wird. Die Klasse kann verschiedene Konstruktoren haben, und durch das attributieren in den eckigen Klammern wird dann der jeweils passende Konstruktor aufgerufen. Das Grundgerüst von MaxValue sieht also einfach so aus:

public class MaxValueAttribute : System.Attribute
{
   private double maxValue;
   public MaxValueAttribute( double maxValue)
   {
      this.maxValue = maxValue;
   }
   double Size
   {
      get
      {
          return this.maxValue;
      }
   }
}

Korrektur: Doch Änderung für SP2

Kleine Korrektur zum Posting von gestern bezüglich des Service Pack2 und unserer Statiksoftware. Heute ( war ja klar das das so kommen musste ...) haben wir dann doch ein Problem entdeckt das beseitigt werden muss. Wir werden uns also nochmals auf die Suche nach weiteren Problemen machen - und dann irgendwann im Laufe der nächsten Tage ein Update für alle Programme veröffentlichen in dem das Problem mit dem SP2 beseitigt sein wird.