WinForms Cursor Handling – C#

Hier ein kurzer Source Code Ausschnitt zur Cursor Behandlung in MDI Forms.

// Cursor var definieren um Cursor zu sichern
 Cursor oldCursor;

// aktuellen Cursor Zustand speichern
oldCursor = this.MdiParent.Cursor;

// Neuen Cursor setzen 
this.MdiParent.Cursor = Cursors.WaitCursor;

// Hier Aktionen ausführen 
------

// Cursor wieder zurück setzen
this.MdiParent.Cursor = oldCursor;

VS2005 :: Web Services Debuggen

Nachdem ich selbst das Problem am Anfang hatte und auch immer wieder von Freunden, Bekannten und Kollegen auf das Thema Debuggen von Web Services unter Visual Studion 2005 angesprochen werde, hier nun ein kleiner Blog Eintrag der beschreibt wie man dabei am besten vorgeht.

Hier zuerst noch einmal das Szenario:

Ich möchte einen Web Service erstellen und während der Entwicklung auf einfachem Wege in der Lage sein die einzelnen Web Methoden debuggen zu können.

Also einfach ein zweites Projekt (Windows Form) in der Projektmappe erstellt, referenz auf den Web Service in der Projektmappe hinzufügen, als Startprojekt festlegen, und fertig.

Anmerkung zum Szenario:

So sollte es gehen, leider geht es aber „noch“ nicht“

Und hier nun die Lösung:

Zuerst einmal genau so vorgehen wie es im Szenario beschrieben ist und dann folgende Einstellungen zusätzlich vornehmen:

In den Projektmappen Eigenschaften in den Allgemeinen Eigenschaften Startprojekt auswählen.

Dort die Option mehrere Startobjekte auswählen und bei den beiden Projekten (der Web Service und das Windows Forms Projekt) die Aktion auf Starten stellen.

Das ganze noch kurz mit OK bestätigen und fertig.

Wenn ich nun in der Windows Form eine Web Methode verwende, kann ich innerhalb der web methode einfach mit F9 einen Haltepunkt (Breakpoint) setzen.

Hoffe das die (schnelle und kurze) Beschreibung vielen Helfen wird.

Windows Service – OnStart mal etwas anders !

Nachdem ich in einem Projekt mit dem Problem kämpfen musste, das einer der für dieses Projekt entwickelten Windows Dienste durch eine aufwendige Initialisierung bis zu einer Minute in der OnStart Methode verweilt hat bis er endlich den Dienst als gestartet anzeigt habe ich mir überlegt wie man diese Problem anders lösen könnte.

Eigentlich war das auch kein wirklich großes Problem, aber da ich auch erst einmal gezielt darüber Nachdenken musste um auf die Lösung zu kommen, denke ich dass vielleicht auch andere erst einmal auf das Problem aufmerksam werden müssen um dann einen anderen Ansatz zum Start der Windows Dienste zu verwenden.

Im Nachfolgenden Beschreibe ich eine einfach Lösung wie man einen Windows Dienst mit Hilfe eines Timers dazu bringt, sofort zu starten, unabhängig davon, ob aufwendige Initialisierungsprozesse für den Dienst durchgeführt werden müssen oder nicht.

Schauen wir und doch einfach mal wie der normale Startvorgang eines Dienstes aussieht:

Hier ein Beispiel wie es normalerweise aussehen kann, wobei osc irgendeine Klasse ist deren Methoden nach deren Initialisierung vom Service verwendet werden:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Diagnostics;

using System.ServiceProcess;

using System.Text;

using System.Timers; 
 


namespace Namespace.Service

{

      publicpartialclassMeinService : ServiceBase

      {

            MeineKlasse osc;

            public MeinService()

            {

                  InitializeComponent();

                  Osc = new Osc();

            } 


            protectedoverridevoid OnStart(string[] args)

            {

                  Osc.Init();

                  Osc.StartAll();

            } 


            protectedoverridevoid OnStop()

            {

                  osc.StopAll();

            } 


            protectedoverridevoid OnContinue()

            {

                  osc.StartAll();

            } 


            protectedoverridevoid OnPause()

            {

                  osc.StopAll();

            } 


            protectedoverridevoid OnShutdown()

            {

                  osc.StopAll();

                  osc.Dispose();

                  osc = null; 


            }

      } 

Wenn nun davon ausgehen dass Osc.Init() und Osc.StartAll() Methoden sind die lange dauern können, dann befindet sich dieser Dienst in der Gesamt Zeit in welcher diese beiden Methoden ausgeführt werden im Dienst- Status StartPending. Dies kann in bestimmten Situationen aber mehr als unerwünscht sein. Und für diesen Fall habe ich folgende Änderungen vorgenommen, die dazu führen, dass der Service sofort nach dem Start wirklich in den Status Running übergeht.

Nachfolgend nun die Lösung für das Problem:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Diagnostics;

using System.ServiceProcess;

using System.Text;

using System.Timers ; 
 


namespace Namespace.Service

{

      publicpartialclassMeinService : ServiceBase

      {

            Timer startTimer = newTimer();

            MeineKlasse osc;

            public MeinService()

            {

                  InitializeComponent();

                  startTimer.Interval = 1000;        // 1 seconds 

                  startTimer.Elapsed += newElapsedEventHandler(startTimer_Elapsed);

                  startTimer.Enabled = false;

            } 


            void startTimer_Elapsed(object sender, ElapsedEventArgs e)

            {

                  startTimer.Enabled = false;

                  osc = MeineKlasse.loadActiveSystems();

                  osc.StartAll();

            } 


            protectedoverridevoid OnStart(string[] args)

            {

                  startTimer.Enabled = true;

            } 


            protectedoverridevoid OnStop()

            {

                  osc.StopAll();

            } 


            protectedoverridevoid OnContinue()

            {

                  osc.StartAll();

            } 


            protectedoverridevoid OnPause()

            {

                  osc.StopAll();

            } 


            protectedoverridevoid OnShutdown()

            {

                  osc.StopAll();

                  osc.Dispose();

                  osc = null; 


            }

      }

} 

Ich habe die Änderungen in Fettschrift dargestellt damit man diese gleich auf Anhieb erkennen kann.
Und die Erklärung ist eigentlich auch selbstredend.
Ich verwende also einen Timer, der vom OnStart Event eine Sekunde nach dem der Service gestartet wurde die eigentlichen Funktionen des Service aktiviert.

Manchmal ist einfach, einfach Einfach !

DNN User Controls Programmierung VB versus C#

Bei der Programmierung von DotNetNuke Modulen gibt es ja wie allseits bekannt die freie Wahl der .NET Programmiersprachen.

Die beiden beliebtesten Sprachen zur Programmierung von DotNetNuke Modulen sind wohl VB.NET und C#.

Bei der Programmierung von User Controls sind jedoch obwohl beides .NET Programmiersprachen sind die Sprachspezifischen Eigenschaften wie zum Beispiel der Unterschied zwischen Groß und Kleinschreibung bei C# im Gegensatz zu VB.NET zu berücksichtigen. Das dies aber nicht die einzigen Unterschiede sind wird spätestens dann ganz deutlich wenn man versucht ein in VB.NET erstelltes User Control als Vorlage für ein C# User Control zu verwenden.

Schauen wir uns das doch einmal am Beispiel des Moduls Event, das ja Bestandteil des Core Produktes DotNetNuke ist, einmal etwas näher an.

Hier der Auszug aus der Events.ascx (mit VB.NET Codebehind)

<TR>

<TD id=colIcon vAlign=top align=center width='<%# DataBinder.Eval(Container.DataItem,"MaxWidth") %>' rowSpan=3 runat="server">

<asp:Image id=imgIcon runat="server" Visible='<%# FormatImage(DataBinder.Eval(Container.DataItem,"IconFile")) <> "" %>'

ImageUrl='<%# FormatImage(DataBinder.Eval(Container.DataItem,"IconFile")) %>' AlternateText='<%# DataBinder.Eval(Container.DataItem,"AltText") %>'>

</asp:Image></TD>

<TD>

<asp:HyperLink id=editLink runat="server" Visible="<%# IsEditable %>" NavigateUrl='<%# EditURL("ItemID",DataBinder.Eval(Container.DataItem,"ItemID")) %>'>

<asp:Image id="editLinkImage" ImageUrl="~/images/edit.gif" Visible="<%# IsEditable %>" AlternateText="Edit" runat="server" resourcekey="Edit"/>

</asp:HyperLink>

<asp:Label id=lblTitle text='<%# DataBinder.Eval(Container.DataItem,"Title") %>' Cssclass="SubHead" Runat="server">

</asp:Label></TD>

</TR>

Unsere besondere Aufmerksamkeit müssen wir dabei vor allem auf die Funktionen DataBinder.Eval() und EditURL() lenken.

Schauen wir uns Diese Syntax am folgenden Beispiel etwas näher an:

Visible='<%# FormatImage(DataBinder.Eval(Container.DataItem,"IconFile")) <> "" %>'

Mit dieser Zeile wird (in VB.NET ) erreicht dass nur wenn ein IconFile vorhanden ist das Control sichtbar ist, sonst wird der Wert Visible auf false gesetzt

Wenn wir eine solche Zeile in einem User Control einsetzen, welches mit C# zusammenarbeiten soll, dann ergeben sich gleich mehrere Problem (Fehlermeldungen während der Programmausführung, nicht beim übersetzen)

Als erstes wird in C# der Ausdruck nicht als If Ausdruck ausgewertet, da er nicht in () eingeschlossen ist.

Also muss das ganze auf jeden Fall schon mal so aussehen:

Visible='<%# (FormatImage(DataBinder.Eval(Container.DataItem,"IconFile")) <> "") %>'

Zu beachten hierbei sind die Klammern am Anfang und Ende der Auswertung

(FormatImage(DataBinder.Eval(Container.DataItem,"IconFile")) <> "")

Jetzt würden aber noch immer Laufzeitfehler entstehen, da C# bei der Typ Auswertung wesentlich kleinlicher (Gott sei Dank) ist, als dies VB.NET ist.

Das nächste Problem liegt in der Behandlung eines Stringvergleiches. in VB.NET ist der Vergleich string1 <> string2 ein gültiger Vergleich. In C# nicht, also müssen wir einen gültigen Vergleich für C# nehmen, der sieht dann so aus: string1 != string2.

Danach muss unser Ausdruck wie folgt aussehen:

Visible='<%# (FormatImage(DataBinder.Eval(Container.DataItem,"IconFile")) !="") %>'

Wenn Sie nun Denken, dass es nun funktioniert, muss ich Sie leider enttäuschen.

DataBinder.Eval() gibt als Datentyp ein abstraktes Objekt zurück, nun versuchen Sie mal einen Vergleich eines Objekt Datentyps mit „“ einem String, das wird C# nicht zulassen.

Also bleibt uns nichts weiter übrig, als das Objekt zu einem String umzuwandeln.

Die Umwandlung können wir wie folgt vornehmen:

DataBinder.Eval(Container.DataItem,"IconFile").ToString()

Somit sieht unser Ausdruck nun wie folgt aus:

Visible='<%# (FormatImage(DataBinder.Eval(Container.DataItem,"IconFile").ToString()) !="") %>'

Der nun hier dargestellte Ausdruck ist nun C# konform und wird keinen Laufzeitfehler mehr erzeugen.

Schauen wir uns nun noch ein zweites Problem unseres Beispiels an:

<asp:HyperLink id=editLink runat="server" Visible="<%# IsEditable %>" NavigateUrl='<%# EditURL("ItemID",DataBinder.Eval(Container.DataItem,"ItemID")) %>'>

Der hier dargestellte Ausdruck ist der typische Code für den Hyperlink, der aus dem Anzeige Control das Edit Control aufruft.

Der nicht C# konforme Teil dieses Ausdrucks ist nachfolgend dargestellt:

NavigateUrl='<%# EditURL("ItemID",DataBinder.Eval(Container.DataItem,"ItemID")) %>'

Wenn wir das bisherige aus diesem Artikel anwenden, dann wissen wir dass wir das aus dem DataBinder.Eval() zurückgegeben Objekt in einem String umwandeln müssen.

So das unser Ausdruck wie folgt aussieht:

NavigateUrl='<%# EditURL("ItemID",DataBinder.Eval(Container.DataItem,"ItemID").ToString()) %>'

Wie ich am Anfang schon bemerkt habe berücksichtigt C# im Gegenteil zu VB.NET die Groß und Kleinschreibung, und somit haben wir mit dem Aufruf der Funktion EditURL ein Problem, da diese in Wirklichkeit eigentlich EditUrl heißt.

Also ändern wir den Ausdruck wie folgt ab:

NavigateUrl='<%# EditUrl("ItemID",DataBinder.Eval(Container.DataItem,"ItemID").ToString()) %>'

Mit dem Wissen dieser notwendigen Änderungen wenn Sie ein User Control in C# verwenden möchten, was eigentlich für VB.NET konzipiert war, können Sie nun die notwendigen Änderungen in User Controls vornehmen so dass diese dann in einem C# DotNetNuke Module verwendet werden können.

Enum Werte aus Konfigurationsdatei auslesen und in Enum Typ umwandeln

Um in einer App.config Datei Enum Werte wieder in eine Variable des Augzählungstypes einzulesen kann folgende Funktion verwendet werden.

Enum.Parse()

Beispiel:

In diesem Beispiel lesen wir den NotifyFilter eines FileSystemWatcher ein:

Der Key in der App.config sieht wie folgt aus:

<add key="fdwNotiFyFilter" value="FileName, DirectoryName, LastWrite" />

Und hier die Vewendung:

fdw.NotifyFilter = (NotifyFilters)Enum.Parse(typeof(NotifyFilters), ConfigurationSettings.AppSettings["NotifyFilter"]);