WPF-Fenster ohne Titelleiste verschieben 👍 👎

Ein WPF-Fenster, dessen Eigenschaft WindowStyle der Wert None zugewiesen ist, besitzt keine standardmäßige Titelleiste mehr – was ja letztlich auch Sinn der Sache ist.

Eine häufig gewünschte und auch meist sehr sinnvolle Funktionalität ist jedoch, dass der Benutzer das Fenster dennoch verschieben können soll. Dies ist – wie so oft, wenn man weiß, wie – sehr einfach zu lösen. Wir registrieren dazu einfach eine Ereignisbehandlung für MouseLeftButtonDown auf einem Steuerelement des Fensters (oder im Zweifelsfall gar auf dem Fenster selbst) und rufen die DragMove-Methode des Fensters auf:
Fenster per DragMove() verschiebbar machen
010203
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {    this.DragMove();}
Schon lässt sich das Fenster wie gewohnt bei gedrückter linker Maustaste verschieben.

Attribute in C# 👍 👎

Attribute in C# sind eine komfortable Möglichkeit, um Klassen, Methoden und andere Member mit Metadaten anzureichern. Diese können anschließend während der Laufzeit per Reflexion ausgewertet werden.

Konkret möchten wir ein Attribut Description erzeugen, mit welchem wir Methoden eine Beschreibung geben können. Wir müssen uns dazu lediglich eine von Attribute abgeleitete Klasse erstellen, die die entsprechende Information aufnehmen kann:
"Description"-Attribut definieren
0102030405060708091011
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]public class Description : Attribute {    public string Text {        get;        set;    }
public Description(string text) { this.Text = text; }}
Über das AttributeUsage-Attribut legen wir dabei fest, dass das Attribut lediglich (einmal) für eine Methode Verwendung finden können soll.

Nun setzen wir das Attribut für die Methode StartImportantAction einer Klasse ImportantClass:
"Description"-Attribut setzen
0102030405060708
public class ImportantClass {    [Description("Führt eine wichtige Aktion aus!")]    public void StartImportantAction() {        /**         * Aktion ausführen        **/    }}
Anschließend können wir jederzeit von anderer Stelle aus auf diese Information zugreifen:
"Description"-Attribut abrufen
0102030405060708
  // MethodInfo ermittelnMethodInfo methodInfo = typeof(ImportantClass).GetMethod("StartImportantAction");
// "Description"-Attribut ermittelnDescription description = methodInfo.GetCustomAttribute<Description>();
// Beschreibung auslesenstring text = description.Text; // "Führt eine wichtige Aktion aus!"
Auf ähnliche Art und Weise entsteht beispielsweise automatisch die Schnittstellenbeschreibung von BitStadt.de. Im MSDN findet sich auch eine Übersicht allgemeiner Attribute des .NET-Frameworks.

PHP-Funktionen in C# 👍 👎

Da ich sehr häufig von (bestimmt bald ehemaligen Smiley: winking) PHP-Entwicklern gefragt werde, wie sich bestimmte Sachen in C# lösen lassen, habe ich mir überlegt, dies ein wenig koordinierter anzugehen.

Deshalb gibt es ab sofort eine passende (Pseudo-)Kategorie "PHP-Funktionen in C#" dazu, welche unregelmäßig um weitere Funktionen ergänzt werden soll. Vorschläge nehme ich gerne entgegen.

HttpHandler in ASP.NET MVC 👍 👎

Manchmal kann es sinnvoll sein, bestimmte Aufrufe einer Webanwendung abseits der "normalen" Vorgehensweise zu behandeln. Konkret soll es darum gehen, Aufrufe mit der Dateiendung ".css" abzufangen, um in den statischen Dateien Platzhalter dynamisch zu ersetzen, was mit CSS selbst nicht möglich wäre. Unser Stylesheet:
Site.css
01020304
body {    background-color: #{backgroundColor};    color: #{color};}
Die Umsetzung ist sehr einfach, wir müssen dazu lediglich eine Klasse erstellen, welche die Schnittstelle IHttpHandler und natürlich auch das gewünschte Verhalten implementiert – der Fantasie sind hier kaum Grenzen gesetzt. Wir belassen es der Einfachheit wegen bei einem einfachen (und nicht sehr effizienten) Beispiel:
HttpHandler implementieren
010203040506070809101112131415161718192021222324
public class HttpHandler : IHttpHandler {    public bool IsReusable {        get {            return true;        }    }
public void ProcessRequest(HttpContext context) { // Ersetzungsdaten (in der Praxis evtl. aus Datenbank) Dictionary<string, string> replacementData = new Dictionary<string, string>() { {"backgroundColor", "000"}, {"color", "fff"} };
// Platzhalter im Stylesheet mit Ersetzungsdaten austauschen StringBuilder css = new StringBuilder(File.ReadAllText("Site.css"));
foreach(KeyValuePair<string, string> replacement in replacementData) { css.Replace(String.Format("{{0}}", replacement.Key), replacement.Value); }
context.Response.Write(css.ToString()); }}
Abschließend passen wir die Konfiguration (→ Web.config) an, um unsere eigene Behandlung zu registrieren:
Konfiguration erweitern
01020304050607
<configuration>  <system.webServer>    <handlers>      <add name="DynamicStylesheet" path="*.css" type="HttpHandler" verb="GET" />    </handlers>  </system.webServer></configuration>
Weiterführende Informationen zum Thema finden sich im MSDN.

Ein bekanntes – und weitaus mächtigeres – Projekt, welches von dieser Möglichkeit Gebrauch macht, ist dotless, eine Implementierung der Stylesheet-Skriptsprache LESS für .NET. Diese ermöglicht u. a. eine übersichtlichere Verschachtelung, Variablen und Funktionen in Stylesheets, wobei der HttpHandler dafür sorgt, dass die vom Browser angeforderten .less-Dateien serverseitig in "reines" CSS umgewandelt und ausgeliefert werden.

Die Verwendung der MVC-Erweiterung für ASP.NET ist für dieses Vorgehen übrigens nicht unbedingt erforderlich, ich arbeite jedoch nahezu ausschließlich mit dieser.

Hashing in C# und PHP 👍 👎

Den meisten PHP-Entwicklern sind die beiden Funktionen md5(…) und sha1(…) geläufig. Diese liefern zu einer übergebenen Zeichenkette einen Streuwert ("Hash") in hexadezimaler Darstellung. Zu diesem Zweck gibt es in C# die beiden Klassen MD5CryptoServiceProvider und SHA1CryptoServiceProvider.

Diesen Klassen kann man über die ComputeHash-Methode unter anderem ein byte-Array übergeben und bekommt daraufhin ein solches zurück, welches den Hash darstellt. Da wir es in der Praxis aber doch meist einfach nur mit Zeichenketten und u. U. auch mit verschiedenen Hash-Algorithmen (z. B. MD5, SHA1) zu tun haben, möchten wir das Ganze in eine komfortable generische Erweiterungsmethode für Zeichenketten verpacken:
Methode implementieren
0102030405060708
public static string GetHash<T>(this string str) where T : HashAlgorithm, new() {    using(T hashProvider = new T()) {          // Streuwert berechnen        byte[] hash = hashProvider.ComputeHash(Encoding.UTF8.GetBytes(str));
return Encoding.UTF8.GetString(hash); }}
Für diejenigen, denen die Arbeit mit generischen Typen (noch) nicht geläufig ist, werde ich in Kürze auch noch einen etwas ausführlicheren Beitrag zu diesem Thema verfassen.

Die Rückgabe dieser Methode dürfte nun jedoch leider noch gar nicht dem entsprechen, was viele erwarten – die hexadezimale Schreibweise wie in PHP, so dass diese Ausgaben insbesondere nicht kompatibel zueinander für Vergleiche sind, was die Interoperabilität natürlich massiv beeinträchtigt. C# liefert standardmäßig nämlich das, was bei den entsprechenden PHP-Funktionen mit dem Parameter $raw_output erhältlich ist.

Da die hexadezimale Darstellung jedoch tatsächlich häufig praktikabler ist, stützen wir uns ausnahmsweise ( Smiley: winking) auf diese Vorgehensweise und bringen C# zu diesem – unter anderem von PHP gewohnten – Verhalten:
Methode implementieren (hexadezimale Rückgabe)
0102030405060708
public static string GetHash<T>(this string str) where T : HashAlgorithm, new() {    using(T hashProvider = new T()) {          // Streuwert berechnen        byte[] hash = hashProvider.ComputeHash(Encoding.UTF8.GetBytes(str));
return BitConverter.ToString(hash).Replace("-", String.Empty).ToLower(); }}
Jetzt liefert unsere Erweiterungsmethode für C# exakt das gleiche Ergebnis wie PHP das standardmäßig macht und kann darüber hinaus besonders einfach und flexibel auf jeder Zeichenkette verwendet werden:
Methode verwenden
01
string hashTest = "test".GetHash<SHA1CryptoServiceProvider>();
Durch Übergabe der gewünschten Implementierung als Typparameter erhalten wir nun direkt das Ergebnis.

Projektverweise

Kategorien / Archiv  |  Übersicht RSS-Feed

Schlagworte

Suche