In München findet am 13. und 14. Februar 2007 die Entwickler-Konferenz VSOne statt. In 8 Tracks werden sehr interessante Sessions rund um die Software-Entwicklung mit .net angeboten:
- Windows Forms - Windows Mobile - Web 2.0 - Advanced Development (ADC) - Visual Basic - SQL Server & BI - Business Fasttrack - Tools&Solutions
Ich werde dort zwei Vorträge halten, einen zum Thema Databinding in Winforms, einen zum Datenaustausch mit mobilen Devices über Active Sync.
Nähere Infos unter www.vsone.de

Will man in einem Web-Service Sessions nutzen, so muss der Client Cookies handeln können. Ist der Client eine Web-Applikation, so ist das kein Problem. Bei WinForms muss man da zu einem kleinen Kniff greifen.
Man muss für den Service einen CookieContainer erstellen. Dazu kann man im Client folgenden Code verwenden:
WebService.MyService ws = new WebService.MyService(); ws.CookieContainer = new CookieContainer();
Damit kann dann auch der Windows-Client Cookies handeln.
Mit Microsoft Sandcastle lassen sich die XML-Kommentare aus dem Sourcecode in eine Dokumentation konvertieren. Damit lassen sich ohne viel Aufwand Dokumentationen im Stile einer MSDN-Dokumentation erstellen, die sogar in die VS-Hilfe eingebunden werden können. Einen Einstieg bietet das folgende Tutorial von Jonas:
http://www.dotnet-ulm.de/Downloads/20061121/Sandcastle.zip
Es gibt ein Control mit dem Namen DSOFramer, das es erlaubt, Office-Anwendungen in eine eigene WinForms-Anwendung zu integrieren. Das Control hat allerdings einen Schönheitsfehler, es funktioniert nicht auf MDIChild-Forms. Versucht man innerhalb eines MDIChilds per Code eine Datei im DSOFramer zu laden, erhält man eine nichtssagende Fehlermeldung. Über einen kleinen Trick lässt sich das Problem allerdings beseitigen. Man baut sich einfach ein Usercontrol, in das man den DSOFramer steckt. danach funktioniert das Control auch in MDIChilds.
Infos und Download des DSOFramer_Controls unter http://support.microsoft.com/kb/311765
Dank an Christopher für den Tipp.
artiso, mein Arbeitgeber, sucht momentan einen .net-Entwickler zur Festanstellung. Falls jemand Interesse hat oder jemanden kennt, der im Moment einen Job sucht, der kann gerne mit mir Kontakt aufnehmen.
Hier die Stellenanzeige:
Die artiso solutions GmbH, ein ein visionäres .net Entwicklungsunternehmen in der Nähe von Ulm sucht zum nächstmöglichen Zeitpunkt einen/eine
.net Entwickler/-in
Die artiso entwickelt individuelle Softwarelösungen für groß- und mittelständische Unternehmen in Süddeutschland. Hierbei kommen sowohl Web- als auch Windows-Technologien und Smart Devices zum Einsatz. Es werden modernste Entwicklungstechnologien, zum Beispiel .net 3.0 ebenso wie innovative Architekturansätze und moderne Entwicklungstools eingesetzt.
Wir bieten unseren Entwicklern-/innen die Möglichkeit, sich mit innovativen Technologien zu beschäftigen. In unserem Team kann sich jeder seinen individuellen Neigungen entsprechend einbringen und Verantwortung übernehmen.
Nähere Informationen erhalten Sie unter http://www.artiso.com/ oder via e-Mail unter tschissler@artiso.com.
Um den aktuell angemeldeten Windows-User zu ermitteln gibt es zwei Möglichkeiten:
1.) string userName = Environment.UserName Diese Variante liest aus der Systemumgebung die entsprechende Einstellung aus. Nachteil: Diese Einstellung kann leicht manipuliert werden, z.B. in der Eingabeaufforderung mit Set USERNAME = Administrator
2.) string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name; Diese Variante fragt den User direkt im Windows Sicherheitsystem ab und kann deshalb nicht manipuliert werden.
Hat man eine umfangreiche Form mit vielen Controls, ist es oft nicht einfach, den Überblick über die Tab-Reihenfolge der Form zu behalten. Und für den Anwender ist es ärgerlich, wenn er bei Tastaturbedienung wild auf der Eingabemaske herum geführt wird. IN VS 2005 gibt es im Menü Ansicht hier einen Eintrag, der hier eine Lösung bietet . Ruft man den Menüpunkt Aktivierreihenfolge (Taborder) auf (ist nur verfügbar wenn das aktive Fenster eine Winform enthält), wird die Form in einem speziellen Modus dargestellt und auch der Cursor ändert sein Aussehen.
Die Zahlen, die nun bei jedem Control angegeben werden, geben die Tabreihenfolge an. Hat man Gruppierungselemente wie z.B. Panels, so werden durch Komma getrennt erst die Reihenfolge der Gruppen und dann die des Controls angezeigt.
Um die Tabreihenfolge zu ändern beginnt man nun einfach die Controls in genau der Reihenfolge anzuklicken, wie man sie haben möchte. Die Zahlen werden sofort angepasst.
Um den Modus wieder zu verlassn, muss man den Menüpunkt im Menü Ansicht einfach wieder deaktivieren. So einfach erhält man saubere Tabreihenfolgen.
Oft hat man das Problem, dass man eindeutige, fortlaufende Nummern erzeugen möchte. In einer MultiUser-Umgebung braucht man dazu eine zentrale Instanz, die gleichzeitige Zugriffe mehrere User korrekt verwaltet, typischerweise eine Datenbank. Mit Oracle z.B. kann man diese Nummern mit Hilfe einer Sequenz erzeugen.
CREATE SEQUENCE SOPTOOLS.SEQSOPNUMMER START WITH 1 INCREMENT BY 1 MINVALUE 0 NOCACHE NOCYCLE NOORDER
Die Parameter sind eigentlich weitgehend selbsterklärend. Die Meisten Beispiele findet man, wenn man nun mit Hilfe des INSERT-Befehls einen neuen Eintrag erzeugen möchte. Das sieht dann ungefähr so aus:
INSERT INTO SOPS (SOPNUMMER, SOPNAME) VALUES (SEQSOPNUMMER.NEXTVAL,'NeueSOP')
Damit wird ein neuer Datensatz angelegt. Dabei wird die Sequenz automatisch um eins erhöht und der neue Wert als SOPNUMMER eingetragen. D.h. wenn der Befehl mehrfach hintereinander ausgeführt wird, hat jeder Eintrag eine eindeutige SOPNUMMER. Mit .CURRVAL kann man übrigens auf die Sequenz zugreifen, ohne dass der Wert erhöht wird.
Bei mir war's aber so, dass ich einfach nur den nächsten Wert der Sequenz wollte ohne einen INSERT. Da muss man zu einem kleinen Trick greifen. Man kann die Sequenz nicht direkt abfragen, sondern immer nur in Verbindung mit einer Tabelle. Hier bietet Oracle die Pseudo-Tabelle DUAL, die für diesen Zweck super geeignet ist. Sie enthält genau eine Zeile mit einer Spalte. Damit liefert folgende Abfrage den nächsten Wert der Sequenz und erhöht die Sequenz automatisch:
SELECT SEQSOPNUMMER.NEXTVAL FROM DUAL
Ich bin jetzt auch auf der Blog-Liste der DtoNetGerman Bloggers gelistet. Einfach mal vorbeischauen, dort sind sehr interessante deutschsprachige Blog versammelt. Link to DotNetGerman Bloggers
Mit dem patterns & practices Guidance Explorer wird dem Entwickler ein Tool an die Hand gegeben, mit dem er entsprechende Entwicklungs-Patterns und Best Practices zu verschiedenen Themen gefunden werden können. Darüber hinaus kann man eigene Checklisten und eigene Guidance-Sets erstellen. Link to patterns & practices Guidance Explorer
Diese Community-Seite beschäftigt sich hauptsächlich mit der Entwicklung von Software für die Windows Media Center Edition. Link to Code-Green.de
Will man eine Liste mit allen Werten eines enums befüllen, z.B. zur Ausgabe in einer DropDown-List, kann man folgenden Code verwenden:
foreach (int Entry in Enum.GetValues(typeof(DataLayer.LogDataLayer.LogDataLayer.LogEntryTypes))) { vl.ValueListItems.Add(Entry, ((DataLayer.LogDataLayer.LogDataLayer.LogEntryTypes)Entry).ToString()); }
Ich erstelle gerade eine Anwendung, die verschiedene Berechnungen durchführt. Um möglichst flexibel zu sein, habe ich jede Berechnungsmethode in eine eigene DLL gepackt. Diese DLLs sollten nun nicht zur Compile-Zeit eingebunden werden sondern erst zu Laufzeit. Dadurch kann man jederzeit zusätzliche Berechnungsmethoden erstellen und diese dann einfach in das Anwendungsverzeichnis kopieren ohne die gesamte Anwendung neu compilieren zu müssen. Das Ganze funktioniert sogar zur Laufzeit, d.h. die Anwendung muss nicht neu gestartet werden, wenn eine neue DLL hinzukommt.
Das Ganze funktioniert so:
- Ich habe ein Interface erstellt, das als Schnittstelle für alle Berechnungsmethoden dient.
public interface IBaseEngine { void StartCalculation(); }
- Dann habe ich ein Berechnungsmodul erstellt, das die Schnittstelle implementiert. Berechnungsmodul und Interface sind im gleichen Namespace:
public class cCapaPlanerEngine : IBaseEngine { public cCapaPlanerEngine() { }
public void StartCalculation() { // Hier kommt die Berechnung } }
- Nach dem Compilieren wird die DLL des Berechnungsmoduls in das Anwendungsverzeichnis kopiert.
- Nun kann das Berechnungsmodul instanziiert werden:
IBaseEngine calculationEngine = (IBaseEngine)Activator.CreateInstanceFrom("CalculationEngines\\" + _CalculationEngineName + ".dll", "ScenarioGenerator.CalculationEngines.c" + _CalculationEngineName).Unwrap();
Da sind noch ein paar statische Sachen drin, die besser in die config ausgelagert bzw. automatisch ermittelt werden, aber so ist es momentan etwas verständlicher. Wichtig ist das Unwrap() am Ende, da sonst der Typecast nicht funktioniert. Eine optimierte Version könnte etwa so aussehen, wobei hier in derm Berechnungsmodul nur eine Klasse stehen sollte:
Assembly calculationEngineAssembly = Assembly.LoadFrom(Properties.Settings.Default.CalculationEnginesPath + "\\" + _CalculationEngineName + ".dll"); calculationEngine = (IBaseEngine)Activator.CreateInstance(calculationEngineAssembly.GetTypes()[0]);
- Nun kann die Berechnungsmethode einfach aufgerufen werden:
calculationEngine.StartCalculation();
Weitere Berechnungsmodule lassen sich nun einfach erstellen indem sie die selbe Schnittstelle implementieren und dann einfach in das Anwendungsverzeichnis kopiert werden.
Man kann eigene enums in den Settings einer Anwendung avblegen. Dazu muss zunächst der enum definiert werden. Anschließend öffnet man die Settings-Datei des Projektes (liegt unter Properties). Im Feld Type kann man hier nun Browse... auswählen. Dann gibt man bei SelectedType den vollqualifizierten Na | |