Unbegrenzte Anzahl an Parametern uebergeben
Mir ist aufgefallen, dass viele gar nicht wissen, dass man Methoden so gestalten kann, dass diese eine unbestimmte menge an Parametern akzeptieren. Das gibt es sowohl in Java als auch in .NET (und wohl jeder anderen höheren Programmiersprache)
Wie sieht das Ganze aus? Naja wenn ihr schon mit C#/.NET Gearbeitet habt werdet ihr wohl nicht um diese Funktion herum gekommen sein:
string var = String.Format("Hallo mein Name ist {0} und ich komme aus {1}", "Bernd", "Kassel");
Die Zahlen in den Geschweiften Klammern sind hierbei Platzhalter, die später über eine Variable gefüllt werden. Von diesen Platzhaltern kann man beliebig viele angeben, dementsprechend müssen dann aber auch genauso viele Parameter mit den Werten angegeben werden.
Wie sieht hier die Deklaration dieser Methode aus?
public void DoSomething(int someValue, params string[] values)
{
foreach (string value in values){
Console.WriteLine(value);
}
}
Diese Methode nimmt nun einen normalen int Parameter an und ab dann können beliebig viele Werte vom Typ String folgen:
DoSomething(12345, "Hallo", "Wer", "Bist", "Du");
Genauso kann man das auch in Java machen, hier ist es sogar etwas schöner gelöst wie ich finde:
//Methoden Deklaration
public DoSomething(int someValue, String... values) {
for(String value : values){
System.out.println(value);
}
}
//Nutzung:
DoSomething(12345, "Hallo", "Wer", "Bist", "Du");
In Java werden hier nach dem Variablentyp drei Punkte angehängt die signalisieren, dass dieser Typ nun beliebig oft folgen kann.
Dabei wird intern aber auch nur ein Array mit den Werten erzeugt, das kann man bei der .NET Variante bereits in der Deklaration erkennen. So lässt sich in Java die main-Methode auch so schreiben, ohne dass es zu Problemen kommt:
public static void main(String... args) {
for(String s : args){
System.out.println(s);
}
}
Es sei an dieser Stelle noch erwähnt, dass der Parameter, der beliebig oft folgen kann immer als letztes angegeben werden muss - aus offensichtlichen Gründen
Diese Schreibweise kann an einigen Stellen für deutlich bessere Lesbarkeit sorgen und vereinfacht einfach nur die Anwendung der Funktionen, sollte man auf jeden Fall schon mal gesehen haben.
Eine eigene Boolean.ToInt Methode bauen
Lächerlich werden nun sicher alle von euch denken, eine ToInt Methode implementieren, die nichts anderes macht als den boolischen Wert in eine 1 umzuwandeln wenn true oder in eine 0 wenn false.
Im Grunde möchte ich euch hier auch zustimmen, denn das ist alles andere als schwer! Aber C# bietet uns hier viele Möglichkeiten um an unser Ziel zu kommen, deswegen habe ich mir gedacht schreibe ich es mal nieder.
Der Einfachste Ansatz ist sicherlich wie folgt:
public int ToInt(bool wert) {
if (wert) {
return 1;
} else {
return 0;
}
}
Diese Funktion arbeitet natürlich tadellos und erfüllt ihren Zweck zu 100%. Aber es geht noch schöner und eleganter wie ich finde. So kann man sich die IF-Bedingung sparen und das Ganze etwas abkürzen:
public int ToInt(bool wert) {
return Convert.ToInt32(wert);
}
Sehr schön, mehrere Zeilen gespart und das Ergebnis ist immer noch das Selbe! Doch das geht noch weiter, man kann sogar hier noch was einsparen, in dem man die tollen Features von C# nutzt:
public int ToInt(bool wert) {
return wert ? 1 : 0;
}
Falls euch die Syntax nichts sagt, wir nutzen hier den "Conditional Operator", der übrigens schon sehr lange existiert. Zu lesen wäre diese Zeile wie die IF-Bedingung aus dem ernsten Versuch. Wenn die Bedingung vor dem Fragezeichen erfüllt (true) ist dann soll die 1 zurückgegeben werden ansonsten die 0.
Ich finde diese Syntax lässt sich sehr gut lesen, und da ein Boolischer Wert nicht null sein kann laufen wir hier auch nicht Gefahr eine Exception auszulösen. Wenn wir das Ganze noch in eine Extension Method packen können wir das auch sehr bequem benutzen:
public static class Class1 {
public static int ToInt(this bool wert) {
return wert ? 1 : 0;
}
public static bool ToBool(this int wert) {
return wert == 1 ? true : false;
}
public static void main() {
bool var = true;
if (var.ToInt() == 1) {
//...
}
int var2 = 1;
bool var3 = var2.ToBool();
}
}
Ich habe hier auch den umgekehrten Weg mit aufgenommen (IntToBool), hier sollte man vielleicht noch erwähnen, dass nur bei einer 1 true zurückgegeben wird, ansonsten wird false abgeliefert egal welchen int Wert man übergibt!
Wie gesagt, das ist nichts Weltbewegendes, aber ich bin nicht gleich drauf gekommen den Conditional Operator hier zu verwenden daher der Blogpost und vielleicht bringt es ja den einen oder anderen von euch auf tolle Gedanken
C#: Threads mit Parametern Starten
Wenn ihr auch mal mit Threads gearbeitet habt habt ihr sicherlich auch schon festgestellt, dass es zu Problemen kommt, wenn man einen Thread starten möchte und diesem auch noch Parameter unterjubeln will.
Ein normaler(einfacher) Threadstart sieht ja folgendermaßen aus:
public class test {
public test() {
Auto a = new Auto();
Thread t = new Thread(new ThreadStart(a.Fahre));
}
}
public class Auto {
public void Fahre(){
//...
}
}
Aber was ist wenn wir nun dem Auto auch sagen sollen wie weit es fahren soll? Also so:
public class test {
public test() {
Auto a = new Auto();
Thread t = new Thread(new ThreadStart(a.Fahre(100)));
}
}
public class Auto {
public void Fahre(){
//...
}
public void Fahre(int wieWeit) {
//...
}
}
Leider geht das nicht so einfach, da ThreadStart einen Methodennamen erwartet. Hier müssen wir also anders ansetzen. Eine Möglichkeit dieses Problem zu lösen bzw. zu umgehen ist es die Klasse Auto etwas zu modifizieren und die Parameter, die wir eigentlich über den Methodenaufruf übergeben wollten über den Konstruktor zu übergeben (oder über Properties zu setzen). Somit wäre die Fahre Methode wieder frei von Parametern und könnte problemlos über ThreadStart aufgerufen werden:
public class test {
public test() {
Auto a = new Auto(100);
Thread t = new Thread(new ThreadStart(a.Fahre));
}
}
public class Auto {
private int wieWeit;
public Auto(int wieWeit) {
this.wieWeit = wieWeit;
}
public void Fahre(){
//... hier kann man mit dem Wert
// von wieWeit arbeiten
}
}
Aber diese "Lösung" ist natürlich auch nicht das Gelbe vom Ei. Deswegen habe ich noch ein wenig gegoogelt und habe eine sehr schöne und zugleich einfache Lösung entdeckt:
public class test {
public test() {
Auto a = new Auto();
ThreadStart start = delegate { a.Fahre(100); };
Thread t = new Thread(new ThreadStart(start));
}
}
public class Auto {
public void Fahre(int wieWeit) {
//...
}
}
Hier machen wir von den Anonymen Methoden Gebrauch (siehe Zeile 5) und packen die in ein Delegate, das wir dann dem ThreadStart übergeben. Hier können wir auch bequem unseren Parameter mit angeben und müssen somit auch nicht an der Klasse selbst Änderungen vornehmen.
Kleiner Nachtrag noch:
Maximilian hat mich grad noch an das ParameterizedThreadStart Delegate aufmerksam gemacht, das habe ich noch unbewusst ausgelassen
. Dieses bietet ebenfalls eine angenehme Möglichkeit Parameter an Threads zu übergeben, hier auch dazu ein kleines Beispiel:
public class test {
public test() {
Auto a = new Auto();
Thread t = new Thread(new ParameterizedThreadStart(a.Fahre));
t.Start(100);
}
}
public class Auto {
public void Fahre(object wieWeit) {
//...
}
}
Man beachte hierbei, dass der Typ des Parameters nun Object ist (Zeile 12) deswegen muss vor der Verwendung noch ein Cast stattfinden. Außerdem könnte man Probleme bekommen, wenn man Überladungen benutzen will.
Das ganze ist natürlich nichts weltbewegendes, aber da ich es noch nicht kannte habe ich es hier mal mit aufgenommen.
C#: ++/– Operator auf eigene Klassen anwenden
Ihr habt den ++/-- (inkrement/dekrement) Operator bestimmt schon tausende Male eingesetzt ohne viel darüber nachzudenken, genau wie ich, doch heute ist mir schlagartig bewusst geworden, dass dieser Operator auch ein paar von meinen Klassen gut stehen würde und die Anwendung und die Lesbarkeit des Codes verbessern würde.
Die Umsetzung gestaltet sich hier zum Glück sehr einfach:
class Program {
static void Main(string[] args) {
Person a = new Person("Alf", 10);
++a;
Console.WriteLine(a.ToString()); //Ausgabe: Alf - 11
a++;
Console.WriteLine(a.ToString()); //Ausgabe: Alf - 12
a--;
Console.WriteLine(a.ToString()); //Ausgabe: Alf - 11
--a;
Console.WriteLine(a.ToString()); //Ausgabe: Alf - 10
Console.ReadLine();
}
}
public class Person {
int Alter { get; set; }
string Name { get; set; }
public Person(string Name, int Alter) {
this.Alter = Alter;
this.Name = Name;
}
public static Person operator ++(Person p){
p.Alter++;
return p;
}
public static Person operator --(Person p) {
p.Alter--;
return p;
}
public override string ToString(){
return this.Name + " - " + this.Alter.ToString();
}
}
Es muss lediglich eine statische Methode in die Klasse eingebunden werden, deren Rückgabewert ebenfalls der Klassentyp ist. Desweiteren folgt vor dem Namen der Funktion das Stichwort "operator" und es muss auch noch ein Parameter vom Typ der Klasse übergeben werden.
Innerhalb dieser Methode können wir nun entscheiden, was passieren soll wenn der Operator benutzt wird. In meinem Fall habe ich mich dazu entschieden, das Alter der Person um eins zu erhöhen, aber der Fantasie sind hier natürlich keine Grenzen gesetzt.
Natürlich kann man auch weitere Operatoren auf diese Weise implementieren, wie zum Beispiel den +/- (Plus/Minus) Operator, dazu gibt es ein nettes Beispiel im MSDN.
Eine feine Sache wie ich finde, nicht kompliziert - kann aber helfen den Code verständlicher und einfacher zu gestalten.
ASP.NET MVC3: Remote Attribut “richtig” nutzen
Seit gestern probiere ich die neuen Attribute in dem ASP.NET MVC3 RC aus und bin eigentlich sehr zufrieden. Nur ein Attribut wollte bisher einfach nicht funktionieren, nämlich das Remote-Attribut.
In den offiziellen Release Notes ist dieses Attribut beschrieben und es wird folgendes Beispiel benutzt um es dem Leser näher zubringen:
Dies habe ich auch als Vorlage genommen und meine Methode im Controller implementiert:
Doch das hat nicht funktioniert. Nun weiß ich auch wieso, denn hier wird ein falsches Ergebnis zurück gesendet. Das Ergebnis dieser Methode liefert ein “False” oder “True” ab, mit einem großen Buchstaben am Anfang – und das macht uns alles kaputt!
Hier ist unser Request den jQuery für uns erzeugt:
Dieser Request kommt erfolgreich auf dem Server an und wird korrekt verarbeitet. Als Response kommt dann folgendes zurück:
Man beachte hier das großgeschriebene “False”. Also arbeitet der Controller völlig korrekt, nur müsste er ein kleines “false” zurückgeben.
Nun wenn man es Quick & Dirty haben will kann man einfach einen String zurückgeben:
Der bessere Weg wäre wohl ein JSON Result:
Nun funktioniert auch alles wie es soll und ich kann ruhig schlafen ![]()
ASP.NET MVC3: Was gibts neues?
Einige von euch haben es sicher mitbekommen, dass vor Kurzem der Release Candidate (RC) von ASP.NET MVC3 veröffentlich wurde. Download, Changelog. Diese neue Version bringt einige für uns Entwickler tolle neue Funktionen und Vereinfachungen mit.
Die wohl auffälligste Neuerung ist die neue ViewEngine namens Razor, diese sorgt dafür, dass die Views um einiges schlanker und lesbarer werden durch die Einführung einer neuen Syntax.
Ich will mit euch ein kleines Beispielprojekt erstellen in dem wir Schritt für Schritt einige der Neuerungen durchgehen.
Fangen wir an und erstellen ein neues MVC3 Projekt in Visual Studio und bereits hier gibts es was Neues zu betrachten:

Bild 1: Der Neue Projekt erstellen Dialog
Da wir von Vorn beginnen möchten erstellen wir ein neues Leeres Projekt und wählen die neue Razor ViewEngine.
Layout
Wenn man nun einen Blick auf den Projektmappenexplorer wirft, wird man drin nicht viel finden, lediglich eine CSS- und zwei cshtml-Dateien. Die cshtml-Dateien fangen auch noch mit einem Unterstrich (_) an und haben irgendwas mit Layout im Namen.
Was ist das?
Öffnen wir zunächst im Shared-Ordner die Datei _Layout.cshtml.
Diese Datei kann man mit einer MasterPage aus MVC2 vergleichen. Wenn ihr genau hinschaut werdet ihr im Title-Tag einen Platzhalter finden und auch im body-div ist einer namens „@RenderBody()“.
Die Layoutseiten in MVC3 funktionieren anders als die in MVC2, auch wenn diese Seite auch Platzhalter besitzt die später mit Inhalt befüllt werden fällt dennoch die Methode RenderBody() auf. Diese Methode ist in jeder Layout-Seite drin und steht immer an der Stelle wo später der Inhalt der Seite stehen wird. Neben der RenderBody()-Methode gibt es auch die RenderSection()-methode, die auch einen Namen bekommen und auch als optional markiert werden können.
Was auch neu ist, ist dass wir keine <% %> Tags mehr haben in die wir den ASP.NET Code schrieben können, das alles übernimmt nun das @-Zeichen. Das System ist dabei so intelligent, dass es erkennt bis wohin der Code geht weswegen man auch kein schließen Tag benötigt. Weitere Informationen zu der Razor Syntax.
Wie man sieht sind die ganzen JavaScript Verweise auskommentiert. Bitte entfernt die Kommentarmarkierung, da wir diese Skripte bald benötigen.
Gut, schleißen wir diese Datei und werfen nun einen Blick in die „_ViewStat.cshtml“ in unserem Views-Ordner:
Der Inhalt hier ist wie man sieht sehr übersichtlich ![]()
Was macht diese Datei nun? Wie man sieht verweist diese auf die _Layout.cshtml die wir eben betrachtet haben, dabei sorgt dieser Verweis dafür, dass alle Views in dem Views-Ordner inkl Unterordner diesen Verweis auch erhalten. Das hat zur Folge, dass man nun nicht mehr in jeder einzelnen View diese Referenz auf die Layoutdatei eintragen muss und spart sich so den redundanten Code.
Viel mehr gibt es dazu eigentlich auch nicht zu sagen. Gehen wir nun zum nächsten Schritt und erstellen eine neue View.
Views
Wenn ihr den View-Hinzufügen Dialog wählt werdet ihr auch hier eine Veränderung feststellen:
Wie man sieht kann man nun auch bei jeder einzelnen View wählen, welche ViewEngine man hier gern verwenden möchte. Legen wir eine gewöhnliche View an.
Die neue View enthält nun nur diese paar Zeilen Code (siehe Bild oben).
Zuerst wird ein Codeblock aufgemacht mit der @{ … } Syntax, das bedeutet, dass nun nur noch ASP.NET Code kommt bis die schließen Klammer kommt, auch über mehrere Zeilen.
Innerhalb dieses Codeblocks füllen wir nun den Titel unserer Seite, wenn ihr euch erinnern könnt wurde diese Variable in der MasterPage im Title-Tag wieder ausgegeben.
Man beachte hier, dass diese Property dynamisch erstellt wird und es die Property „Title“ eigentlich gar nicht gibt. Diese wird dann zur Laufzeit generiert und mit Inhalt befüllt. So kann man beliebig viele solcher Properties anlegen.
In Zeile 3 geben wir an welche MasterPage hier verwendet werden soll, da wir aber bereits die Datei „_ViewStat.cshtml“ in unserem Views-Ordner liegen haben müssen wir innerhalb der View keinen Verweis mehr auf eine Masterpage setzen. (Außer wir wollen eine andere Nutzen) Also können wir diese Zeile aus unserem Code löschen.
Nun fängt schon ab Zeile 6 der normale HTML Quelltext an, ohne dass wir irgendwo einen Zugehörigkeitsbereich definiert haben. Das ist ein weiteres MVC3 / Razor Feature, denn alles wird an der stelle in der MasterPage eingesetzt wo wir die Methode RenderBody() aufrufen. Eine Ausnahme besteht, wenn wir Sektionen in der Masterpage definiert haben, diese würden dann dementsprechend der passenden Sektion zugeordnet werden.
So könnte eine Sektion aussehen:
Das wars nun soweit zu dieser View. Wenn ihr mögt könnt ihr nun weiter damit arbeiten wie mit einer gewöhnlichen View.
Nun wollen wir mal ein Formular anlegen, dass wir zum Registrieren eines Benutzers nutzen wollen. Dazu benötigen wir zunächst ein Model auf das wir dann unsere View mit der Form typisieren.
Legen wir also eine neue Klasse im Models-Verzeichnis an. Die Model Klassen verhalten sich in MVC3 eigentlich genauso wie in MVC2, nun sind aber einige neue Attribute hinzugekommen die ich euch hier mal vorstellen möchte:
Wie ihr seht hat meine Modelklasse 5 Eigenschaften. Die ersten drei sind mit dem Attribut [Required] markiert und sind somit Pflichtfelder. Alle Eigenschaften besitzen ein [DisplayName()] Attribut, dass den Text enthält, der später in der View angezeigt werden soll.
Kommen wir nun zu den neuen Attributen. Erstmal das [Required, Compare(…)] Attribut. Dieses Attribut sorgt hier dafür, dass „RepeatEmail“ mit „Email“ verglichen wird und übereinstimmen muss damit die Validierung erfolgreich ist. So müssen wir diese zwei Werte nun nicht mehr im Controller manuell vergleichen.
Weiter unten bei der About-Eigenschaft finden wir ein weiteres neues Attribut namens [SkipRequestValidation] – Im Prinzip sagt der Name schon alles aus. Dieses Attribut sorgt dafür, dass diese Property beim Binding keine Exception wirft wenn dort HTML enthalten ist.
Früher musste man dann im Controller die Action mit einem [ValidateInput(false)] markieren, was natürlich immer noch funktioniert, aber nun kann man auch einzelne Properties bequem markieren ohne gleich für die ganze Methode den Validationinput abzuschalten.
Hier gibts es nun sogar die Möglichkeit bestimmte Properties von der Validierung auszuschließen:
Hier werden die Properties “Body” und “Summary” nicht auf HTML Inhalt überprüft.
Wie ihr sehen könnt habe ich ein Attribut auskommentiert. Auf dieses Attribut habe ich mich persönlich sehr gefreut, aber es scheint nicht zu funktionieren (oder ich mache etwas falsch, wenn ihr meinen Fehler seht bitte kommentieren ACHTUNG: dazu habe ich hier ein Update geschrieben)
Dieses RemoteAttribut erlaubt es eine Eigenschaft an eine Methode in einem Controller zu binden und währen der Ausführung der View beim Client im Hintergrund über Ajax aufzurufen. Für den Fall von der Property Name würde die Methode UserNameAvailabla im Controller Register aufgerufen werden, welche ein boolean zurück gibt. So wird dann dynamisch eine Fehlermeldung auf der View erscheinen.
Wenn man dieses RemoteAttribut nun benutzen möchte muss man natürlich die oben angegebene Methode im angegebenen Controller implementieren, zB so:
Diese Methode wird dann beim Validieren per Ajax aufgerufen und zeigt dann dementsprechend auch eine Fehlermeldung an (Falls nötig):
Zum Schluss möchte ich noch darauf hinweisen, dass ich ein bestimmtes kleines Feature vermisst habe, nämlich eine bequeme Möglichkeit einen String auszugeben ohne diesen mit HTML zu Encoden. Denn soweit bietet Razor leider keine Möglichkeit dafür. Deswegen muss man hier mit einer eigenen kleinen Extension Methode aushelfen.
Das wäre es dann nun auch für heute. Ich habe ein kleines Beispiel Projekt vorbereitet, dass ihr hier herunterladen könnt. (.NET 4.0 VS2010)
C#: Eigene Dialoge erstellen
In der Windows Forms Welt benutzt man Dialoge sehr häufig, egal ob es der OpenFileDialog, SaveFileDialog, PrintDialog, ColorDialog oder einfach nur die simple MessageBox ist, sie erleichtern uns der Leben sehr. So wäre auch ein Dialog sehr nützlich der Benutzereingaben entgegen nimmt und uns diese dann weitergibt, doch so einen Dialog finden wir nur im VisualBasic Namespace in .NET.
Bild 1: Das InputBox Dialogfenster
Der InputBox Dialog nimmt Eingaben vom Benutzer entgegen und gibt diese an unser Programm weiter. Doch was wenn wir den Benutzer nach einem Passwort fragen möchten? InputBox kann den eingegebenen Text leider nicht maskieren. So muss ein eigener Dialog für die Passworteingabe her.
Zum Glück ist diese Aufgabe im .NET Framework wirklich schnell erledigt. In VB.NET gibt es unter Windows Forms sogar extra eine Vorlage für ein Dialogfenster. Aber nun mal Langsam.
Alles was wir benötigen ist ein normale Klasse die von System.Windows.Forms.Form erbt. Dieses Fenster könnt ihr nun so gestalten, wie ihr euch euer Passwortdialogfenster so vorstellt. Ich habe meins so gestaltet:
Bild 2: Mein PasswortDialog Fenster
Bevor wir uns nun an die Innereien dieser Fensterklasse machen müssen wir noch ein paar Kleinigkeiten mit dem Designer vornehmen. Wir müssen nämlich angeben, welche Aktionen zu welchen Dialog Ergebnis führen.
So soll das Klicken des OK-Buttons das DialogResult "OK" Auslösen, der Abbrechen-Button und der X-Button (Fenster schließen) aber das "Cancel" DialogResult. Dementsprechend stellt man die gleichnamige Eigenschaft der Buttons auf "OK" oder "Cancel".
Um dem Benutzer später das Arbeiten mit diesem Fenster intuitiver zu machen kann man nun noch den Form Eigenschaften "AcceptButton" und "CancelButton" die passenden Buttons zuweisen. Das sorgt dafür dass der Benutzer später das Dialog Fenster mit der Taste "Enter" bestätigen oder mit "Escape" abbrechen kann.
Bereits jetzt, ohne auch nur eine Zeile Code geschrieben zu haben funktioniert dieses Fenster wie ein vollwertiger Dialog. Sogar die Buttons, für die wir keinen Code hinterlegt haben schließen beim Klicken das Fenster und übergeben das passende DialogResult.
Alles was wir nun noch machen müssen ist, Parameter anzubieten mit denen wir den Text auf dem Formular modifizieren können und vielleicht die Anzahl der Buttons die angezeigt werden sollen:
public partial class PasswordDialog : Form {
/// Das vom Benutzer eingegebene Passwort
public string EnteredPassword {get; private set;}
/// Erzeugt ein neues Password Dialog
public PasswordDialog(string windowTitle, string messageTitle,
string messageDescription,
DialogButtons buttons = DialogButtons.OKCancel,
bool windowClosable = true) {
InitializeComponent();
//Übergebene Werte übernehmen
this.Text = windowTitle;
this.lblTitle.Text = messageTitle;
this.lblDescription.Text = messageDescription;
//Optionale Parameter bearbeiten
if (buttons == DialogButtons.OK) {
//Wenn nur der OK Button angezeigt werden
//soll den Cancel Button ausblenden
this.cmdCancel.Visible = false;
}
if (windowClosable == false) {
//Schließen Button bei Bedarf ausblenden
this.ControlBox = false;
}
EnteredPassword = ""; //Property initialisieren
}
private void PasswordDialog_Load(object sender, EventArgs e) {
}
private void cmdCancel_Click(object sender, EventArgs e) {
//Dem Aufrufer mitteilen, dass der Dialog abgebrchen wurde
//this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
}
private void cmdOK_Click(object sender, EventArgs e) {
//Eingabe übernehmen
EnteredPassword = txtPassword.Text;
}
}
public enum DialogButtons {
OK = 0,
OKCancel = 1
}
Hier passiert eigentlich nichts aufregendes, im Konstruktor werden nur alle übergebenen Parameter auf das Formular übertragen (Text, Buttons...) und die Property für das Passwort initialisiert. Schließlich wird noch bei dem Klick auf den OK-Button der Text in der TextBox noch in der Property gespeichert und dann wird das Formular auch schon mit dem passenden DialogResult geschlossen.
Wenn wir das Ganze nun nutzen wollen dann kann das wie folgt aussehen:
private void cmdShowDialog_Click(object sender, EventArgs e) {
PasswordDialog pass = new PasswordDialog("Passwort benötigt",
"Bitte geben Sie Ihr Passwort an",
"Wenn Sie Zugriff auf erweiterte " +
"Funktionen benötigen müssen Sie Sich" +
"mit Ihrem Passwort Authentifizieren");
DialogResult res = pass.ShowDialog();
if (res == System.Windows.Forms.DialogResult.OK) {
this.txtDialogResult.Text = pass.EnteredPassword;
} else {
this.txtDialogResult.Text = "Der Benutzer hat den Dialog abgebrochen";
}
}
Bild 3: Die DemoAnwendung
Das wars auch schon. So schnell hat man einen eigenen Dialog erstellt.
An dieser Stelle noch der Hinweis, dass der oben gezeigte Quelltext nur mit .NET 4.0 kompiliert werden kann, da ich hier Optionale Parameter benutzt habe. Wenn ihr diese rausnehmt dann läuft dieser Code problemlos auch mit älteren .NET Versionen.
Hier habe ich für euch auch noch ein kleines Demoprojekt gebastelt:
Download: VS2010 C# .NET4.0
ASP.NET MVC 2: Custom ErrorPages anlegen
Wenn man Webseiten entwickelt möchte man diese natürlich möglichst anschaulich für den Nutzer gestalten, und dazu gehört es auch für den Benutzer anschauliche und auch verständliche Seiten zu präsentieren, auch wenn mal ein Fehler auftaucht. Im Normalfall passen die Default-Fehlerseiten von ASP.NET leider nicht ins Bild der restlichen Seite, weswegen wir gezwungen sind unsere eigenen Fehlerseiten anzulegen.
Bild 1: Typische 404 Fehlermeldung von ASP.NET
Eigene Fehlerseiten sind unter ASP.NET MVC 2 schnell in vier Schritten eingerichtet.
1. Änderungen an der Web.config vornehmen
Zunächst müssen in der Web.config die customErrors eingeschaltet werden. Hier können die Attribute "defaultRedirect", welches die Adresse definiert die im Falle eines Fehlers aufgerufen wird und "mode", dass einstellt ob Fehler angezeigt werden sollen oder nicht.
Mit den inneren "error"-Ästen kann man dazu noch spezifische Seiten zu einzelnen Fehlercodes zuweisen. Man kann hier sowohl eine absolute Adresse angeben oder nur eine relative. Für alle nicht spezifizierten Errorcodes wird die Url aus dem customError Tag benutzt.
Wenn ihr diese Einstellungen Lokal testen wollt dann solltet ihr auch den "mode" auf "On" stellen, da ihr euere Seiten sonst nicht zu Gesicht bekommt.
2. Anlegen des Controllers für die Fehlerbehandlung
Wie ihr sehen könnt habe ich hier eine lokale Adresse angegeben. Hierbei wird der Controller "Error" aufgerufen und je nach Fehlercode eine andere Methode.
Im Controller haben wir hier eigentlich nichts besonderes:
Ich war an dieser Stelle mal faul und habe nur eine einzige View für alle Fehler angelegt, die dann die übergebene message ausgibt. Dazu kommt noch, dass wir der Response noch den passenden HttpStatusCode übergeben, da manche Anwendungen danach gehen und so prüfen, ob ein Aufruf erfolgreich war.
3. Die View
Wie eben erwähnt macht die View in meinem Beispiel nichts anderes als den Inhalt der Messagevariable auszugeben. Hier könnt ihr natürlich eurer Kreativität freien Lauf lassen und auch für jeden Error eine einzelne View anfertigen.
4. Glogal.asax - Catch All Route registrieren
Zum Schluss sollten wir noch eine sogenannte Catchall Route einrichten, die wir nach allen unseren Routen positionieren damit diese nur greifen kann, wenn keine der anderen gepasst hat, diese Route wird in jedem Fall aufgerufen, wenn keine der vorderen gepasst hat.
Wenn die CatchAll Route greift wird der Home Controller aufgerufen und die Action "NotFound" ausgeführt.
Im Grunde sind wir nun fertig, alle von uns eingetragenen Fehler werden nun abgefangen und durch von uns präparierten Seiten ersetzt. Das einzige was noch passieren kann ist dass ihr im IIS andere ErrorPages eingestellt habt, dann dann werden diese angezeigt und nicht die von euch erstellten. Hier müsst ihr die "Error Responses" auf "Detailed errors" stellen.
.NET 4.0 Entfernung zwischen zwei Punkten (Koordinaten) berechnen
Letztens habe ich wieder mal in .NET Framework rum gewühlt und bin dabei über den System.Device.Location Namensraum gestolpert. Dieser bietet einige tolle Funktionen die man sich mal anschauen sollte.
Dieser Namensraum existiert seit .NET 4.0 und ist dazu da um die mit Windows 7 eingeführten Sensoren zu nutzen, wie den Bewegungssensor usw. (Siehe Bild)
Wie es der Namensraum schon sagt geht es hier um den Location Sensor. Leider habe ich keinen Rechner oder Laptop der über ein GPS Chip verfügt auf dem ich diese Funktionalität testen könnte. Aber das war mir auch nicht so wichtig, denn eigentlich war ich auf der Suche nach einer Möglichkeit Entfernungen zu berechnen anhand von Koordinaten.
Ich war schon kurz davor eine eigene Funktion zu basteln, als ich diesen Namensraum sah. Zum Glück, denn ich muss sagen, denn Microsoft hat hier wirklich gute Arbeit geleistet, so ist es möglich mit einem Einzeiler die Entfernung zwischen zwei Koordinaten zu errechnen. Hier ein Beispiel:
using System.Device.Location;
private void Form1_Load(object sender, EventArgs e) {
GeoCoordinate bielefeld = new GeoCoordinate(52.020833, 8.535); //Ja, das gibt es wirklich
GeoCoordinate muenchen = new GeoCoordinate(48.139722, 11.574444);
double meters = bielefeld.GetDistanceTo(muenchen); // => 483,303 km
}
Wie man sieht ist ist das wirklich sehr sehr einfach. Natürlich bietet dieser Namensraum noch viel mehr, so kann man beispielsweise auch EventListener einrichten, die Events feuern wenn sich das Gerät bewegt und sich die Koordinaten somit ändern. Ein Beispiel dazu findet ihr hier.
.NET Objekte zwischen Formularen verfuegbar machen
Immer häufiger sehe ich in Foren die Frage, wie man Informationen (Objekte) zwischen Formularen zugänglich machen kann. Dies ist eigentlich kein großes Unterfangen, wenn man erstmal verstanden hat wie es funktioniert.
Die VB-Programmierer werden hier wohl schon das Wort "Global" auf der Zunge liegen haben, aber wer diesen Artikel von mir gelesen hat, weis, dass ich das nicht gerne mag und deswegen euch hier andere Wege aufweisen werde.
Das Problem
Unser Problem ist, dass wir beispielsweise zwei Formulare haben, bei denen Form2 auf Informationen von Form1 zugreifen will. Da Objekte in .NET isoliert von einander laufen kann ein Objekt nicht einfach auf das andere zugreifen. Man muss diese Beiden Objekte mit einander bekannt machen bzw. diese mit einander verknüpfen.
Dieses Verknüpfen erreicht man mit Objektreferenzen. Dabei muss die Form die die andere Form aufruft eine Referenz auf das Objekt hinterlegen, dass dem anderen Formular bekannt sein soll und dieses an das fremde Form übergeben.
Die Lösung
Das beschriebene Vorhaben kann man auf verschiedenen Wegen erreichen, die sich aber relativ ähnlich sind. Ich möchte hier zwei recht ähnliche Methode zeigen, und eine die sich etwas unter scheidet.
Methode 1
Die Form die Informationen aus einer anderen Form benötigt erhält einen neuen Konstruktor der als Parameter die gewünschte Variable bekommt:
string wertAusForm1 = "";
public Form2(string info) {
InitializeComponent(); //Wichtig!
wertAusForm1 = info;
}
Hierbei ist "info" die Variable die wir aus der Form1 übergeben bekommen, diese ist vom Typ String, aber natürlich könnt ihr diese nach eurem Bedarf anpassen. Und auch in der menge seid ihr nicht begrenzt, ihr könnt den Konstruktor um beliebig viele Parameter erweitern. Wichtig ist, dass die "InitializeComponent()" Methode aufgerufen wird, falls ihr das Formular mit dem Visual Studio Designer gemacht habt, damit auch alle Komponenten initialisiert werden.
Aufruf aus Form1:
private void button1_Click(object sender, EventArgs e) {
Form2 frm2 = new Form2(textBox1.Text);
frm2.Show();
}
Der im Parameter übergebene Wert wird dann in der Klassen-variable "wertAusForm1" gespeichert und ist nun für das ganze Formular verfügbar.
Diese Methode ist sehr simpel und schnell implementiert, doch wird es zum Problem, wenn man viele Variablen übergeben möchte, so schwellen die Konstruktoren schnell mal auf mehrere Zeilen an. An diesem Problem setzt methode 2 an.
Methode 2
Diese Methode unterscheidet sich kaum von der vorherigen, doch diesmal wollen wir viele Variablen übergeben, unseren Konstruktor aber nicht unnötig aufblasen. Hier bietet es sich an das ganze Formular als Parameter zu übergeben um auf alle Objekte des Formulars Zugriff zu erhalten. So haben wir nur einen Parameter aber Zugriff auf alle variablen.
Form3 Konstruktor:
//METHODE 2
public Form3(Form1 form) {
InitializeComponent();
aufrufendeForm = form;
this.label2.Text = aufrufendeForm.textBox2.Text + " - " +
aufrufendeForm.textBox3.Text + " - " +
aufrufendeForm.textBox4.Text + " - " +
aufrufendeForm.textBox5.Text + " - " +
aufrufendeForm.textBox6.Text;
}
Aufrufcode in Form1:
private void button2_Click(object sender, EventArgs e) {
Form3 frm3 = new Form3(this);
frm3.Show();
}
Wie man sieht, übergibt man hier als Parameter "this" sprich, sich selbst und in dem neuen Formular hat man dann bequem Zugriff auf alle TextBoxen von Form1. Bei dieser Methode muss man allerdings aufpassen dass die Objekte auf die man zugreifen will auch sichtbar, also public sind.
Dazu muss man den Form.Designer öffnen und ganz unten bei der Deklaration der Objekte die Sichtbarkeit auf Public ändern:
Bild1: Sichtbarkeitsänderung der Steuerelemente
Leider bringt auch diese Variante ein paar Unannehmlichkeiten mit sich, so muss die Klasse die die Informationen benötigt (hier Form3) genau wissen, von welcher Form diese aufgerufen werden kann und es im Konstruktor definieren. So kann man nicht ohne Aufwand Form3 aus einer weiteren Form aufrufen, da diese bereits Streng Typisiert auf Form1 eingestellt ist.
Methode 3
Die wohl sauberste Methode ist es wohl ein eigenes Objekt als Parameter zu übergeben. Dies hat den Vorteil, dass es für den ganzen Namensraum verfügbar ist und alle Klassen es definieren können und auch wieder verwenden können.
Dazu legen wir uns eine neue Klasse an in der wir Properties zu allen Informationen erstellen, die wir weiter geben möchten:
public class Informationen {
public string info1 { get; set; }
public string info2 { get; set; }
public string info3 { get; set; }
public string info4 { get; set; }
public string info5 { get; set; }
}
Ich arbeite hier nur mit String Variablen, aber natürlich kann hier jeder beliebige Typ stehen. Vor dem Aufruf eines neuen Formulars können wir nun eine Instanz dieser Klasse bilden und mit unseren Werten befüllen um es anschließend als Parameter an die neue Form zu übergeben.
Form3 Konstruktor:
//METHODE 3
public Form3(Informationen infos) {
InitializeComponent();
this.infos = infos;
this.label2.Text = infos.info1 + " - " +
infos.info2 + " - " +
infos.info3 + " - " +
infos.info4 + " - " +
infos.info5;
}
Und der Aufruf aus dem Aufrufer Formular (Form1):
private void button3_Click(object sender, EventArgs e) {
Informationen infos = new Informationen();
infos.info1 = textBox2.Text;
infos.info2 = textBox3.Text;
infos.info3 = textBox4.Text;
infos.info4 = textBox5.Text;
infos.info5 = textBox6.Text;
Form3 frm3 = new Form3(infos);
frm3.Show();
}
Auf diese Weise kann jedes beliebige Formular Informationen an Form3 übergeben ohne weitere Änderungen in Form3 vornehmen zu müssen. Die Klasse Informationen ist hier natürlich sehr leicht und schnell erweiterbar, sodass alle gewünschten Informationen schnell weiter gegeben werden können.
Alles wirklich nicht kompliziert, aber da ich es immer öfter antreffe dachte ich der Artikel könnt nützlich sein.
Hier habe ich noch das Demo Projekt zum Download:
Demoprojekt: Download [VS 2010]

