 | Marco Hagenschulte, Betreiber von www.wsus.de, hat das Gewinnspiel „Tools für WSUS 3.0“ gestartet. Gesucht wird ein nützliches selbst-entwickeltes Werkzeug für die Windows Server Update Services 3.0 (Add-On, Sidebar Gadget, Scripts, usw.). Zum Gewinnspiel |
Habe gerade den ersten Praxis-Test mit Microsoft SharedView absolviert. Das hat auf Anhieb geklappt, echt klasse.
Das Tool erlaubt es, dass man eine Session einrichtet und die Teilnehmer der Session untereinander ihre Desktops oder auch nur einzelne Anwendungen freigeben können. Dabei können die anderen entweder nur zuschauen oder auch aktiv eingreifen. Das tolle dabei ist, dass für alle Teilnehmer eine einfache Internet-Verbindung genügt, auch für den Session-Initiator.
Ich wollte gerade einen externen Kollegen bei einer Fehlersuche unterstützen. Am Telefon war das aber kaum zu erklären. Wir haben einfach beide SharedView runtergeladen und installiert. Die Verbindung hat auf Anhieb geklappt, obwohl wir beide hinter einer Firewall sitzen. ich konnte mich auf seinen Desktop schalten und diesen bedienen. Das Ganze ist noch nicht sehr schnell, aber es handelt sich dabei ja noch um eine Beta-Version und hoffentlich wird das Release in Punkto Performance noch etwas zulegen. Das einzige, was am Anfang zu etwas Verwirrung geführt hat, war, dass der Kollege mir zwar die Kontrolle über seinen Desktop übertragen hat, die dann aber immer gleich wieder zurücksprang. Wir haben dann aber schnell rausgefunden, dass die Kontrolle wieder zurückgeht, wenn am Freigabe-Rechner die Maus bewegt wird. Wenn man's weiss, eigentlich gar nicht so schlecht.
Ich fand das Ding echt superklasse und wir konnten den Fehler recht schnell beheben. (Sicher schneller als per Telefon und auch schneller als wenn wir erst den remote desktop auf der Firewall hätten freischalten lassen müssen)
Microsoft SharedView Beta
Microsoft Surface ist eine neue revolutionäre Oberfläche, ein Tisch, ein Display, alles in einem und von allem etwas. Jedenfalls ist Microsoft Surface eine gigantische neue Möglichkeit, mit dem Computer zu interagieren, ohne Tastatur, ohne Maus. Ich hoffe, das Ding wird bald auch in Deutschland irgendwo zu bestaunen sein. Es lohnt sich, schon mal einen Blick auf die schöne neue Welt von morgen zu werfen. Microsoft Surface
Regionerate ist ein kleines Tool mit dem sich automatisch verschiedene Code-Elemente wie Properties, Methoden, Konstruktoren in separate Regions zusammenfassen lassen. Die entsprechenden Codezeilen werden dabei automatisch in bereits existierende Regions verschoben und hier sortiert. Die Regeln für die Gruppierung lassen sich anpassen. Ein kleiner Screencast zeigt, was das Tool alles kann. Damit entfällt nun endlich das lästige manuelle Sortieren der Felder und Properties. Regionerate Gefunden bei Dani Meier
Die nächsten Termine der .net Developer-Group Ulm sind: 02.08.2007 - 18:00 Uhr Thema: LINQ – Language Integrated Query 05.09.2007 - 18:00 Uhr Thema: Windows Workflow Foundation in ASP.NET Nähere Details unter www.dotnet-ulm.de
Ich werde in nächster Zeit bei einigen Usergroups unterwegs sein und einen Vortrag zum Thema Team Foundation Server halten. Die Termine sind momentan: 24.07.07 .net Developers Group München 25.09.07 bonn-to-code.net 01.10.07 .Net Usergroup Leipzig 31.10.07 .Net Developers Group Stuttgart Thema: Team Foundation Server in der Praxis Mit Team Foundation Server bietet Microsoft zusammen mit Visual Studio Team System ein leistungsfähiges System zur Organisation des gesamten Software Lifecycles. Die Key-Features sind: -
Verwaltung von Funktionsanforderungen, Aufgaben und Fehlern -
Quellcode-Verwaltung und Branching-Strategien -
Buildmanagement -
Überwachung von Projektmetriken und Reporting Wie diese Funktionen in der Praxis genutzt werden können und ob dies auch von kleinere Teams sinnvoll eingesetzt werden können, beleuchtet dieser Vortrag. Darüber hinaus werden einige Beispielszenarien aus der Praxis live vorgeführt. Weitere Termine sind in Vorbereitung. Wer noch Interesse an einem Vortragstermin hat, kann sich gerne an mich wenden.
Markus Alt hat in seinem Blog einen Link zu einem Whitepaper, das die Umsetzung eines Entwicklungsprozesses nach dem V-Modell XT mit Hilfe des Team Foundation Servers beschreibt. Das Dokument ist als PDF und als MSDN-Artikel verfügbar.
Ich nutze von meinem Notebook eine VPN-Verbindung über WLAN. Dabei habe ich immer wieder das Problem, dass die VPN-Verbindung behauptet, ich brauche zuerst eine Internet-Verbindung um die VPN-Verbindung nutzen zu können obwohl die Internet-Verbindung steht.
Inzwischen habe ich rausgefunden, dass das an den Virtal Ethernet Adapter liegt, die VMware auf meinem Rechner installiert haben. Wenn ich diese Adapter disable, dann funktioniert die VPN-Verbindung auf Anhieb.
In Excel kann man ein Textfeld anlegen und diesem einen variablen Inhalt geben. Hierzu markiert man das Textfeld und gibt in der Formelzeile z.B. einen Verweis auf eine Zelle ein (=A1). In A1 kann nun eine beliebige Formel stehen, z.B. ="Summe: " & SUMME(A2:A20). Möchte man in den text einen Zeilenumbruch einfügen, dann kann man die Funktion ZEICHEN(10) verwenden, also z.B. = "Summe 2006: " & SUMME(A2:A20) & ZEICHEN(10) & "Summe 2007: " & SUMME(B2:B20)

Seit Anfang Mai bin ich nun CLIP-Mitglied. Leider bin ich im Moment derart im Stress, dass ich erst jetzt dazu komme das hier zu bloggen. Leider leidet unter meiner aktuellen Arbeitsbelastung auch mein Blog, den ich momentan sehr vernachlässige, aber das wird sich hoffentlich bald wieder ändern.
http://www.microsoft.com/germany/community/programme/clip.mspx
Gerade hatte ich mal mit den Settings für Winform-Anwendungen etwas rumgespielt und bin dabei darauf gestoßen dass man auch für Klassenbibliotheken eine Settings-Datei anlegen und darin Werte erfassen kann. Die Frage war nun, wie kann ich diese Werte einstellen, wenn ich die Klassenbibliothek in eine Anwendung integriere? Nach einigem Googeln und Testen hier nun meine Ergebnisse:
- Die Konfiguration der Anwendung inkl. aller Klassenbibliotheken werden über eine zentrale konfigurationsdatei (app.config bzw. <Anwendungsname>.exe.config) vorgenommen.
- Die Konfigurationsparameter der Klassenbibliothek werden in diese zentrale Konfigurationsdatei leider nicht automatisch übertragen.
- Werden keine Konfigurationsparameter für die Klassenbibliothek angegeben, behält diese ihre Default-Werte (das sind die, die beim Kompilieren in der app.config der Klassenbibliothek standen). Diese Default-Werte sind in der Settings.Designer.cs hinterlegt und werden in die DLL reinkompiliert.
- Man kann diese Default-Werte übersteuern, indem man in der app.config der Anwendung einen zusätzlichen Settings-Block einfügt (im unteren Beispiel der Bereich ClassLibrary1.Properties.Settings). Diesen kopiert man am besten aus der app.config der Klassenbibliothek. Wichtig ist, dass dieser neue Block noch registriert wird. Dies passiert im Bereich <configSections> mit der Zeile.
<section name="ClassLibrary1.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
Sonst erhält man eine Exception, dass die Configuration ungültig ist.
Nun kann man aus der Anwendung heraus auch die Parameter der Klassenbibliothek einstellen. Ich habe das z.B. verwendet um mir die Übergabe von Konfigurationsparametern an die Klassenbibliothek zu ersparen.
Was mir allerdings nicht besonders gut gefällt, ist die Tatsache, dass ich beim hinzufügen von neuen Config-Parametern für die Klassenbibliothek immer daran denken muss, auch in der Anwendung diese hinzuzufügen. Vergesse ich das, erhalte ich zwar keinen Fehler aber es wird einfach mit dem Default-Wert gearbeitet. Das kann manchmal durchaus erwünscht sein, in anderen Fällen ist das aber eher problematisch.
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > <section name="WindowsApplication1.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> <section name="ClassLibrary1.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </sectionGroup> </configSections> <applicationSettings> <WindowsApplication1.Properties.Settings> <setting name="Setting" serializeAs="String"> <value>abc</value> </setting> </WindowsApplication1.Properties.Settings> <ClassLibrary1.Properties.Settings> <setting name="Setting" serializeAs="String"> <value>zzzz</value> </setting> </ClassLibrary1.Properties.Settings> </applicationSettings> </configuration>
Wird ein Connection-String in der config-Datei abgelegt, sollte man darin das Kennwort verschlüsseln. Der Connection-String sieht dann ungefähr so aus:
Data Source=MeinServer;Persist Security Info=True;User ID=User1;Password=vM17E6mtBos=;Unicode=True
Wenn man den Connection-String nun verwenden möchte, muss man darin das Passort erst einmal finden, entschlüsseln und dann im Connection-String das verschlüsselte Kennwort mit dem entschlüsselten ersetzen. Zum Entschlüsseln habe ich eine kleine Funktion eingesetzt, die einfach die Funktionen aus dem System.Security.Cryptography-Namespace verwendet. Das Suchen des Passworts mache ich dann mit einem RegEx:
private string Decrypt(string _connectionString) { Regex r = new Regex(@"^.*?Password=(?<Password>[^;]*)(;|$)", RegexOptions.IgnoreCase); string encrypted = r.Match(_connectionString).Groups["Password"].Value; string decrypted = Decrypt(encrypted, key); return _connectionString.Replace(encrypted, decrypted); }
Nachtrag:
OK, OK, auf dieses Post habe ich zum ersten mal seit ich blogge Kommentare bekommen und das gleich dutzendweise. Leider funktioniert die Bestätigungsfunktion für die Kommentare bei meinem Blog momentan nicht, da muss ich mal schauen.
Die meisten Kommentare bezogen sich darauf, dass man die config-Datei ja auch mit .net Bordmitteln einfach verschlüsseln kann. In meinem Fall war aber der Wunsch im Vordergrund, dass nur das Kennwort verschlüsselt werden sollte. Der Server sollte im ConnectionString frei editierbar sein. Und das ist meines Wissens nach mit den Standardmethoden nicht möglich. Gut, das hätte ich vielleicht im Post etwas klarer rausstellen sollen, aber...
Trotzdem hier als Ergänzung ein paar Links, die aus den Kommentaren, die das Thema Verschlüsselung der config-Datei beschreiben.
http://www.primetime-software.de/rouven.haban/PermaLink,guid,603e3d04-c67e-4837-9f9b-bc9fc3a15b9c.aspx
http://aspnet.4guysfromrolla.com/articles/021506-1.aspx
Hoffe damit sind nun alle zufrieden. Eigentlich ist es schon erstaunlich, dass man auf einen "schlechten" Post Antworten ohne Ende bekommt, auf die normalen oder vielleicht den einen oder anderen guten tut sich da gar nichts. Na ja, vielleicht überlege ich mir einfach in Zukunft hin und wieder Murks zu schreiben, ist doch recht interessant zu sehen, wer so alles meine Posts liest.
Mit der statischen Codeanalyse in VS kann der Quellcode nach verschiedenen Regeln analysiert werden. Es lassen sich auch eigene Regeln erstellen. Beginnt man damit zu arbeiten, ergibt sich die Frage, wie kann man die benutzerdefinierten Regeln und die Einstellung, welche Regeln verwendet werden sollen auf mehrere Projekte und für mehrere Entwickler anwenden.
Dazu ein paar Überlegungen:
1.) Benutzerdefinierte Regeln können durch Kopieren der entsprechenden DLL-Dateien auf die einzelnen Rechner verteilt werden. Dies kann z.B. über das Login-Script erledigt werden.
2.) Die Einstellungen welche Regeln aktiviert sind, sind im Projekt hinterlegt. Über die Quellcodeverwaltung nutzen somit alle Entwickler, die das Projekt bearbeiten, die gleiche Einstellung.
3.) Um die Einstellungen für neue Projekte zu übernehmen bietet sich die Erstellung einer entsprechenden Projektvorlage an, in der die entsprechenden Einstellungen vorgenommen werden. Wird ein neues Projekt auf dieser Vorlage erstellt, so erbt dieses die Einstellungen aus der Vorlage.
Gruppierungen in Excel sind eine feine Sache. Möchte man allerdings untenstehendes Beispiel gruppieren, ergibt sich ein Problem.
Die Gruppenzeile soll in diesem Fall oben stehen. Standardmäßig geht Excel aber davon aus, dass die unterste Zeile einer Gruppe bei einer eingeklappten Gruppierung übrig bleibt. Damit sieht dann das Resultat in dem Beispiel so aus, dass die Gruppe gar nicht mehr angezeigt wird:
Es gibt eine Möglichkeit, dies über eine Einstellung zu ändern. In Excel 2003 findet man die Menü Daten / Gruppierung und Gliederung / Einstellungen. In Excel 2007 ist die Einstellung etwas versteckt. Unter Data befindet sich im Bereich Outline rechts unten ein kleines Kästchen.

Klickt man darauf, dann öffnet sich ein Fenster, in dem man nun die Option Summary rows below detail abwählen kann.
Damit kann man die Gruppierung nun wie gewünscht einstellen.
Noch ein kleiner Tipp: Mit Shift + Alt + Pfeil rechts kann man die Gruppierung auch per Tastatur für die aktuell markierten Zeilen einstellen. Shift + Alt + Pfeil links hebt die entsprechende Gruppierung auf.
Das PropertyGrid ist ein sehr hilfreiches Control, mit dem man einfach die Inhalte der Properties einer Klasse an der Oberfläche anzeigen und bearbeiten kann. Ich hatte hierzu schon zwei Posts : Verwendung des Property-Grids, Dateien und Ordner im Property-Grid auswählen
Das Property-Grid stößt allerdings an seine Grenzen, wenn man damit mehrsprachige Umgebungen unterstützen möchte. Die Anzeige im PropertyGrid ist immer direkt vom Namen der Properties abgeleitet und die Description etc. wird über Attribute angegeben, die nicht über Ressource-Files lokalisiert werden können.
Auf Code-Project habe ich ein erweitertes Property-Grid gefunden, das genau dieses Problem beseitigt.
Link to PropertyGrid utilities - The Code Project - C# Programming
Danke an Chris für den Link!
Vor allem wenn man mit Services programmiert, hat man oft die Anforderung, dass beim Debuggen mehrere Projekte innerhalb der Solution gestartet werden müssen, z.B. ein Service und ein entsprechender Client. Der manuelle Weg war hier, dass man den Service als Startup-Projekt eingertragen hat, das debuggen startet und dann auf den Client im Solution Explorer mit der rechten Maustaste klickt und dann hier Debug / Start new Instance auswählt. Es gibt aber auch noch eine elegantere Möglichkeit. Auf der Eigenschaftsseite der Solution (rechte Maustaste / Properties) kann man unter Startup Project auch die Option Multiple startup projects wählen. Hier kann man nun bei mehreren Projekten die Action auf Start bzw. Start without debugging einstellen. Sogar die Startreihenfolge der einzlnen Projekte lässt sich definieren. Damit starten nun die eingestellten Anwendungen auf einmal.
Will man eine Liste nach XML serialisieren, die über ein Interface definiert ist, dann funktioniert das nicht. Es bleibt hier wohl nur die Möglichkeit, einen eigenen Serialisierer zu schreiben. In meinem Fall konnte ich das umgehen, indem ich auf das Interface verzichtet habe. Sollte jemand hier eine gute Idee haben, dann wäre ich für ein kurzes Feedback dankbar um das zukünftig zu berücksichtigen. Im Moment heißt das für mich, dass beim Serialisieren Interfaces tabu sind.
Ein Beispiel für eine nicht serialisierbare Liste ist z.B.
List<IMyInterface>
Bei der Dotnet Usergroup Bremen wurde das Thema in einem kleinen Artikel ausführlich diskutiert. Link to DOTnet Usergroup Bremen Danke an Chris für den Link
Eine umfangreiche Sammlung von Videos für die Entwicklung mit ASP.Net finden sich unter dem unten stehenden Link. Dabei wird ein weites Themenfeld abgedeckt. Vom Umstieg von ASP.Net 1.1 auf ASP.Net 2.0, Einstieg in ASP.Net 2.0, ASP.Net AJAX und auch zuküftige Themen wie LINQ, BLINQ etc. Link to ASP.NET-Videos für jeden Entwickler
Will man die Kalenderwoche zu einem Datum herausfinden, dann kann man die Funktion GetWeekOfYear nutzen.
CalendarRow.Week = Application.CurrentCulture.Calendar.GetWeekOfYear(CurrentDate, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
Diese Funktion hat allerdings einen kleinen Bug. So wird beispielsweise für den 31.12.2007 KW 53 zurückgegeben. Der darauffolgende Tag, ein Dienstag, ist dann allerdings in KW 1. Eigentlich müssten die Tage einer Woche aber immer in der selben KW sein. Abhilfe schafft hier eine kleine Korrektur. Wir haben ja eingestellt, dass unsere Woche am Montag beginnen soll (DayOfWeek.Monday) und dass die Woche immer dann als KW 1 betrachtet werden soll, wenn wenigstens 4 Tage davon im neuen Jahr liegen (System.Globalization.CalendarWeekRule.FirstFourDayWeek). Der Trick ist nun, dass man einfach immer 3 Tage hinzuzählt, wenn das gesuchte Datum zwischen Montag und Mittwoch liegt. Damit wird aus dem Montag Donnerstag, aus Dienstag der Freitag und aus dem Mittwoch ein Samstag. Da der Donnerstag der Tag ist, von dem abhängt, ob die Woche im neuen oder im alten Jahr liegt, haben wir Montag bis Mittwoch einfach nach hinten geschoben, so dass diese auf jeden Fall im neuen Jahr liegen und damit auch korrekterweise die KW 1 ergeben.
CalendarRow.Week = Application.CurrentCulture.Calendar.GetWeekOfYear(CurrentDate.DayOfWeek >= DayOfWeek.Monday && CurrentDate.DayOfWeek <= DayOfWeek.Wednesday?CurrentDate.Add(new TimeSpan(3,0,0,0)):CurrentDate, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
Mit diesem kleinen Plugin kann man Code-Ausschnitte direkt aus VS mit dem Windows Live Writer bloggen. Das Plugin übernimmt dabei die komplette Formatierung. Die Farbcodierung von VS bleibt dabei erhalten. Link to BlogMyCode VS2005 plugin
Ralf Westphal war am 20.03 in Ulm. Von 10:00 bis 17:00 konnten ihn in einer Kaffeehaus-Konsultation Entwickler mit Fragen löchern. Das Angebot wurde rege angenommen.
Sogar die regionale Presse hat über das Ereignis berichtet.
Danach hielt Ralf im Rahmen des Treffens der .net Developer-Group Ulm einen Vortrag zur Komponentenorientierung in der Software-Entwicklung.

 George Shepherd hat eine Vielzahl von wirklich guten Tipps & Tricks zur Windows- und Web-Programmierung in zwei FAQ-Listen zusammengetragen. Wirklich ein Quell von Anregungen, Problemlösern und Tipps & Tricks. Nicht nur zum Nachschlagen, sondern auch mal zum durchlesen empfohlen. Link zu Windows Forms FAQ Link zu ASP.NET FAQ
Um den Inhalt einer DataRow in eine andere DataRow zu kopieren kann einfach folgende Anweisung verwendet werden:
newRow.ItemArray = ( object[])copyRow.ItemArray.Clone();
Am 20. März ist Ralf in Ulm, um eine seiner berühmten Kaffehauskonsultationen im Cafe Bellavista zu geben. Wer sich also schon immer mal mit einem ausgewiesenen Experten in Sachen .net über ein Problem oder eine Idee unterhalten wollte, der kann jetzt die Gelegenheit nutzen - kostenlos! In der entspannten Umgebung eines Cafes lässt sich über vieles angenehmer diskutieren als auf Konferenzen oder sonstigen Veranstaltungen. Interessenten sollten sich unbedingt vorher bei Ralf per Mail anmelden.  Link to One Man Think Tank Gedanken: Kaffeehauskonsultation in Ulm
Das PropertyGrid ist ein sehr hilfreiches Control, mit dem man einfach die Inhalte der Properties einer Klasse an der Oberfläche anzeigen und bearbeiten kann. Ich hatte hierzu schon zwei Posts : Verwendung des Property-Grids, Dateien und Ordner im Property-Grid auswählen
Das Property-Grid stößt allerdings an seine Grenzen, wenn man damit mehrsprachige Umgebungen unterstützen möchte. Die Anzeige im PropertyGrid ist immer direkt vom Namen der Properties abgeleitet und die Description etc. wird über Attribute angegeben, die nicht über Ressource-Files lokalisiert werden können.
Auf Code-Project habe ich ein erweitertes Property-Grid gefunden, das genau dieses Problem beseitigt.

Link to PropertyGrid utilities - The Code Project - C# Programming
Danke an Chris für den Link!
In dem folgenden Beispiel wird aus einer Auflistung der Typ der Elemente ermittelt und anschließend eine neue Instanz dieses Typs angelegt. Dann werden die Properties die über DisplayMember und ValueMember übergeben wurden mit Werten befüllt. Damit kann die Liste ergänzt werden, ohne Zugriff auf den Datentyp zu haben. Einzige Voraussetzung ist, dass in der DataSource bereits Elemente vorhanden sind.
foreach (cListEntry item in Items) { Type t = ((IList)dataSource)[0].GetType(); object o = Activator.CreateInstance(t); if (this.DisplayMember!= null && this.DisplayMember!= "") t.GetProperty(this.DisplayMember).SetValue(o, item.Text, null); if (this.ValueMember!= null && this.ValueMember!= "") t.GetProperty(this.ValueMember).SetValue(o, item.Value, null); }
Nachtrag:
Wenn der Typ, von dem eine neue Instanz erzeugt werden soll, keinen parameterlosen Konstruktor hat, funktioniert das obige Beispiel nicht. Abhilfe kann man hier schaffen, indem man einen parameterlosen Konstruktor anlegt und diesen als private deklariert. Dadurch kann ich beim Instanzieren weiterhin sicherstellen, dass Pflichtangaben gemacht werden, weil der parameterlose Konstruktor ja nicht sichtbar ist.
Mit object o = Activator.CreateInstance(t, true); kann nun in obigem Beispiel eine Instanz des Objektes durch Aufruf des privaten parameterlosen Konstruktors erzeugt werden. Hier muss man natürlich jetzt sicherstellen, dass die Pflichtobjekte entsprechend befüllt werden.
 Am Dienstag werde ich auf der VSOne zwei Vorträge halten 13:45 - 14:45 Databinding in WinForms für Fortgeschrittene Databinding ist mehr als die oft gezeigten Drag&Drop-Beispiele. Vor allem mit Objekten, typisierten DataSets und User Controls eröffnen sich enorme Möglichkeiten. Diese Session fasst die wichtigsten Infos aus jahrelanger Projekterfahrung zusammen.
15:15 - 16:15 Active Sync Wie bekomme ich Daten vom PC auf mein Mobile Device? Wie kann ich Daten auslesen? Diese Session zeigt, wie dieser Datenaustausch mit Hilfe von Active Sync bewerkstelligt werden kann und sie gibt wertvolle Hinweise, was in der Praxis zu beachten ist. Würde mich freuen, wenn der eine oder andere Leser meines Blogs auch auf der VSOne ist und wir uns mal persönlich kennenlernen.
Ich falle immer wieder darauf rein, deshalb jetzt mal zum merken! Das funktioniert nicht: foreach (DataRow dr in table1.Rows) table2.Rows.Add(dr); Das führt zu einer Fehlermeldung "This row already belongs to another table.". Statt dessen muss das lauten: foreach (DataRow dr in table1.Rows) table2.ImportRow(dr);
Wer Anwendungen für Pocket PCs oder andere mobile Geräte entwickelt oder präsentieren möchte, findet einige hilfreiche Tools im Windows Mobile Developer Power Toys Paket, das kostenlos heruntergeladen werden kann. Unter anderem findet man darin das ActiveSync Remote Display, mit dem man den Bildschirm des PDAs auf dem PC darstellen und den PDA sogar mit der Maus und der Tastatur des PCs steuern kann.  Link to Download details: Windows Mobile Developer Power Toys
Die Workitems von Team System lassen sich ja einfach in Excel abfragen und bearbeiten. Jedoch war ich mit den angeboteten Spalten nicht zufrieden. Man kann zwar über einen entsprechenden Button noch beliebige weitere Spalten abrufen, das aber jedesmal zu tun war dann doch ein wenig nervig. Nach einigem Suchen habe ich dann die Lösung gefunden. Man muss sich einfach eine eigene Query anlegen und dort die gewünschten Spalten definieren. Wenn man nun über diese Query die Workitems in Excel abfragt, kommen genau die Spalten, die in der Query definiert sind.
Mit OleDB lassen sich sehr einfach Excel-Dateien lesen. Man macht sich einen Connectionstring der ungefähr so aussieht:
Dim connectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & ExcelFileName & ";Extended Properties='Excel 8.0;HDR=No;"
Nun kann man eine ganz normale Connection öffnen und wie gewohnt z.B. über ein Select-Statement ein DataSet befüllen.
Dim conn As OleDbConnection = New OleDbConnection(connectionString) conn.Open() Dim dt As DataTable = New DataTable() Dim oleDbDataAdapter As OleDbDataAdapter = New OleDbDataAdapter("SELECT * FROM [Tabelle1]", conn) oleDbDataAdapter.Fill(dt) oleDbDataAdapter.Dispose() oleDbDataAdapter = Nothing conn.Close()
Das Problem ist dabei, wenn in Excel z.B. Integer und Textwerte in einer Spalte gemischt stehen und die Integerwerte dabei überwiegen, wird diese Spalte als Integer angelegt und die Textwerte stehen im Dataset dann als NULL. Das kann man umgehen, wenn man am Connectionstring den Parameter IMEX=1 anhängt. Damit wird ein "ImportMixedTypes"-Mode aktiviert, der gemischte Spalten immer als Text interpretiert.
Dim connectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Me.tbImportdatei.Text & ";Extended Properties='Excel 8.0;HDR=No;IMEX=1'"
Das Problem bei der ganzen Sache ist nur, dass nun standardmäßig die ersten 8 Zeilen geprüft werden. Sind diese alle Integers, wird die Saplte auch als Integer definiert, auch wenn weiter unten noch Textwerte kommen. Man findet hier an verschiedenen Stellen den Hinweis auf einen weiteren Parameter MaxScanRows. Dieser scheint aber nicht zu funktionieren, wie man auch aus diesem MSDN-Artikel ersehen kann. Statt dessen muss man die Einstellung in der Registry vornehmen, wenn man eine andere Anzahl prüfen möchte. Hierzu passt man im Zweig
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Excel
den Parameter TypeGuessRows an. Dieser Wert kann auf 1-16 Zeilen eingestellt werden. Ein Wert von 0 bedeutet dass die ersten 16384 Zeilen geprüft werden, um festzustellen, ob der mixed Mode verwendet werden muss oder ob der Datentyp eindeutig bestimmt werden kann. Dass das eigentlich keine saubere Lösung ist, ist klar. Wer will schon seinen Kunden zumuten, in der Registry rumzupfuschen? Aber es scheint im Moment keine bessere Lösung zu geben.
HDR=No bedeutet im obigen Fall übrigens, dass die Excel-Datei keine Header-Zeile hat.
Team Foundation Sidekicks ist eine Sammlung von Tools, die verschiedene Aufgaben bei Nutzung und Verwaltung von Team Foundation Server erleichtern. Unter anderem wird eine vereinfachte Verwaltung von Labels angeboten:

Link to Team Foundation Sidekicks
Lars Keller berichtet über das Tool IEeee, das es ermöglicht, direkt aus dem IE einen Fehlerbericht mit detailierten Informationen als WorkItem im Team System Server anzulegen. Das Tool dürfte vor allem für Tester sehr interesant sein. Link to IEeee: Home
Scrum for Team System ist ein kostenloses add-in für Visual Studio Team System, das agile Entwicklungsmethoden nach Scrum unterstützt.
Link to Scrum for Team System
Um einen Label auf einer WinForm per Code einfach fett zu machen, funktioniert leider folgende Methode nicht:
TitleLbl.Font.Bold = true;
Statt dessen kann man aber folgenden Code verwenden:
TitleLbl.Font = new Font(TitleLbl.Font, FontStyle.Bold);
WorkItems für den Team Foundation Server lassen sich einfach per Code erstellen.
TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer("tfs-test");
WorkItemStore store = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
WorkItemType wiType = store.Projects[0].WorkItemTypes[1];
WorkItem newWI = new WorkItem(wiType);
newWI.Title = "Title";
newWI.Save();
Für den Code müssen noch folgende Namespaces referenziert und eingebunden werden:
using Microsoft.TeamFoundation;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
Dazu muss das Visual Studio SDK installiert sein.
Zu beachten ist, dass die Angaben für die Eigenschaften des WorkItems sprachspezifisch sind. Auf einem deutschen Server wird folgender Code nicht laufen:
newWI.State = "Active";
Auf dem deutschen Server muss das dann heissen:
newWI.State = "Aktiv";
Unschöner zu lesen, aber dafür sprachunabhängig ist die Verwendung von IDs.
Um übrigens ein Workitem zu lesen, kann folgender Code verwendet werden:
WorkItem newWI2 = store.GetWorkItem(92);
Möchte man einen enum-Wert an eine ComboBox binden, dann muss man hier einen kleinen Trick anwenden. Ich habe das mal am Beispiel mit dem UltraComboEditor aus der Infragistics-Bibliothek realisiert. Man braucht zunächst einen Parse_Event auf dem Binding:
this.ultraComboEditor1.DataBindings[0].Parse += new ConvertEventHandler(ValueInputEnum_Parse);
Dann kann man in dem Eventhandler den Wert in den Enum konvertieren:
void ValueInputEnum_Parse(object sender, ConvertEventArgs e) { e.Value = Enum.Parse(typeof(ePeriodInterval), e.Value.ToString()); }
Unter .net 1.1 hat man das Problem, dass Panels und andere scrollbaren Controls keinen Event liefern, wenn das Control gescrollt wird. Wie man das beheben kann, beschreibt Rick Brewster hier: http://blogs.msdn.com/rickbrew/archive/2004/06/24/165493.aspx
Bei .net 2.0 besteht das Problem übrigens nicht mehr, hier bringen die Controls den Event auch Eigenschaften über die horizontale und vertikale Bildlaufleiste mit.
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 Namen inkl. Namespace ein. Nun kann man in der Spalte Value über eine DropDownList den gewünschten Wert für die Konfiguration auswählen. In der app.config sieht das dann so aus: < CalculationUnitApplication.Properties.Settings> <setting name="Setting" serializeAs="String"> <value>CapaPlaner</value> </setting> </CalculationUnitApplication.Properties.Settings> Auf den Eintrag kann man dann aus dem Code so zugreifen: Properties. Settings.Default.mySetting wobei mySetting der Name ist, der dem Eintrag in der Settings-Einstellung im Feld Name vergeben wurde. Das Ganze ist jetzt typsicher, d.h. wenn jemand die Config-Datei bearbeitet und gibt einen Wert ein, der nicht im enum vorkommt, wird eine Exception geworfen.
Weder was zum Essen noch glänzt es, aber man wird reicher damit, zumindest an Wissen. Die MSDN-Nuggets sind Kurzfilme, die in 10-15 Min. Schritt für Schritt in ein Thema einführen. Gut davbei ist, dass man nach Thema und nach dem Niveau (Einsteiger - Experte) suchen kann.
Link to MSDN Nuggets
Wenn auf einer DataTable ein ColumnChanged-Event eingesetzt wird um bei Änderungen eines Wertes in der DataTable andere Werte in der selben table neu zu berechnen, ergibt sich das Problem, dass das zurückschreiben der neuberechneten Werte wieder zu einem ColumnChanged führt, was den Evbenthandler erneut aufruft und so in einer Endlosschleife endet, die mit einem StackOverflow endet.
Hier gibt es eine recht simple Abhilfe. Man deregistriert den EventHandler bevor die geänderten Werte geschrieben werden und registriert ihn danach einfach wieder. Das kann dann z.B. so aussehen:
void myTable_ColumnChanged(object sender, DataColumnChangeEventArgs e) { myDataSet.myTable.ColumnChanged -= new DataColumnChangeEventHandler(myTable_ColumnChanged); RecalculateValues(); myDataSet.myTable.ColumnChanged += new DataColumnChangeEventHandler(myTable_ColumnChanged); }
Folgender Code zeigt, wie man in eine Zelle im Infragistics-Grid Prozentwerte aus- und eingeben kann. Zu beachten ist hierbei, dass beim BeforeExitEditMode auf die Text-Eigenschaft zugegriffen werden muss, da der Value zu diesem Zeitpunkt noch nicht gesetzt ist.
private void ugShiftDetails_BeforeEnterEditMode(object sender, CancelEventArgs e) { if (this.ugShiftDetails.ActiveCell.Column.Key == "PercentColumn") { UltraGridCell c = this.ugShiftDetails.ActiveCell; c.Value = ((double)c.Value) * 100; } }
private void ugShiftDetails_BeforeExitEditMode(object sender, Infragistics.Win.UltraWinGrid.BeforeExitEditModeEventArgs e) { if (this.ugShiftDetails.ActiveCell.Column.Key == "PercentColumn") { UltraGridCell c = this.ugShiftDetails.ActiveCell; try { c.Value = Double.Parse(c.Text) / 100; } catch { MessageBox.Show("Invalid Input"); } } }
Die Lebensdauer eines Hosts und damit auch der Instanzen der darin enthaltenen Member kann über ein Attribut gesteuert werden. Mein konkreter Anwendungsfall war, dass ich einen Status speichern wollte, der von allen Clients über die gesamte Laufzweit meines Servers abgefragt werden kann. Der Host sollte dazu am einfachsten während der gesamten Laufzeit des Servers als einzige Instanz zur Verfügung stehen. Dazu einfach folgendes Attribut zur Host-Definition hinzufügen: [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] public class cClientHost : IClientInterface Über dieses Attribut lässt sich z.B. die Lebensdauer auch für die auer einer Session einrichten.
Die Fa. artiso (www.artiso.com) für die ich arbeite, sucht momentan einen .net Entwickler. Der Entwickler sollte über folgende Kenntnisse bzw. Eigenschaften verfügen:
- C#, SQL, Winforms, ASP.Net
- Projekterfahrung
-
Selbständiges Arbeiten
-
Qualitätsbewußtsein
Wenn jemand Inteeresse hat bzw. jemand kennt, der Interesse hat, können nähere Informationen unter tschissler@artiso.com erfragt werden.
|