Archiv

Artikel Tagged ‘C#’

Strings Sortieren wie im Windows-Explorer

7. März 2015 Keine Kommentare

Der Windows Explorer sortiert Dateinamen seit den letzten Windows-Versionen so, wie es Menschen erwarten und nicht so, wie es Programmierer tun – er beendet also die Ära der Dateinamen die mit 01, 02, usw. geendet haben. Er macht dies möglich indem er erkennt, wenn Zahlen vorhanden sind und Dateinamen so sortiert, wie es Menschen erwarten. Z.B. wird aus den Dateien

  • A1B.txt
  • A10B.txt
  • A2B.txt

die sortierte Folge

  1. A1B.txt
  2. A2B.txt
  3. A10B.txt

Im Gegensatz zur lexikographischen Sortierung, welche die 10 vor die 2 setzen würde. Gesucht wurde als eine Methode zwei Strings miteinander zu vergleichen, und Zahlen als Zahlen zu verwenden. Dazu müssen beide Strings von vorne durchlaufen werden und jeweils in Zahlenteile und Text/Symbol-Teile unterteilt werden, welche dann jeweils miteinander verglichen werden können.

Dazu habe ich folgende Klasse implementiert, die von IComparer<string> erbt und so wiederverwendbar ist:

public class NumericStringComparer1 : IComparer<string> { private static char DecimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator[0]; public NumericStringComparer1() { SortDirection = ListSortDirection.Ascending; } public string PropertyName { get; set; } public ListSortDirection SortDirection { get; set; } /// <summary> /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other. /// </summary> /// <param name="x">The first object to compare.</param> /// <param name="y">The second object to compare.</param> /// <returns> /// A signed integer that indicates the relative values of <paramref name="x" /> and <paramref name="y" />, as shown in the following table.Value Meaning Less than zero<paramref name="x" /> is less than <paramref name="y" />.Zero<paramref name="x" /> equals <paramref name="y" />.Greater than zero<paramref name="x" /> is greater than <paramref name="y" />. /// </returns> public int Compare(string x, string y) { int result = 0; if (x == null) result = -1; else if (y == null) result = 1; else { int i = 0, j = 0; double dx, dy; string sx = null, sy = null; while (i < x.Length && j < y.Length) { sx = GetStringPart(x, i, out i); sy = GetStringPart(y, j, out j); if (sx == null && sy == null) { // We only get the numbers, if we need to dx = GetNumericPart(x, i, out i); dy = GetNumericPart(y, j, out j); result = dx.CompareTo(dy); // For Numbers as Strings, which are equal, the string-length is also relevant if (result == 0) result = i.CompareTo(j); } else if (sx == null) result = -1; else if (sy == null) result = 1; else { result = sx.CompareTo(sy); } i = Math.Min(i + 1, x.Length); j = Math.Min(j + 1, x.Length); if (result != 0) break; } } if (result != 0 && this.SortDirection != ListSortDirection.Ascending) result *= -1; return result; } /// <summary> /// Gets the numeric value from the string starting at the given startIndex. /// The endIndex is set to the last character that is numeric /// If no numeric value is found, Double.NaN is returned. /// </summary> /// <param name="stringVal">The string value.</param> /// <param name="startIndex">The start index.</param> /// <param name="endIndex">The end index.</param> /// <returns></returns> internal static double GetNumericPart(string stringVal, int startIndex, out int endIndex) { double ret = Double.NaN; StringBuilder sb = new StringBuilder(); bool decimalAdded = false; endIndex = startIndex; for (int i = startIndex; i < stringVal.Length; i++) { if (char.IsNumber(stringVal[i])) { sb.Append(stringVal[i]); } else if (decimalAdded == false && stringVal[i] == DecimalSeparator) { decimalAdded = true; sb.Append(stringVal[i]); } else { break; } endIndex = i; } if (sb.Length > 0) ret = double.Parse(sb.ToString()); return ret; } /// <summary> /// Gets the string part from the given string starting at the given index. /// If nos string-part is found (meaning there is a number at the given startIndes), null is returned /// and the endIndex is set to the startIndex. /// /// </summary> /// <param name="stringVal">The string value.</param> /// <param name="startIndex">The start index.</param> /// <param name="endIndex">The end index.</param> /// <returns></returns> internal static string GetStringPart(string stringVal, int startIndex, out int endIndex) { endIndex = startIndex; bool stringFound = false; for (int i = startIndex; i < stringVal.Length; i++) { char c = stringVal[i]; if (char.IsDigit(stringVal[i]) == false) { endIndex = i; stringFound = true; } else { break; } } if (stringFound) { return stringVal.Substring(startIndex, endIndex - startIndex + 1); } else return null; } }

KategorienProgrammierung Tags: ,

CurrentPrincipal in einer Unity-WPF-Anwendung setzen

10. Oktober 2014 Keine Kommentare

Bei der Untersuchung von Claims Authentifizierung mit WPF ​innerhalb einer mehrschichtigen Anwendung bin ich auf ein Problem gestoßen, den aktuellen (Windows-) Benutzer zu setzen.

Die Anwendung verwendet Unity und somit auch einen entsprechenden Bootstrapper, welcher von UnityBootstrapper erbt. Ich wollte also innerhalb von InializeShell im Bootstrapper auch den aktuellen Benutzer setzen bzw. Claims für den aktuellen Benutzer hinzufügen.

Laut mehreren Orten im Web kann dies ja per Thread.CurrentPrincipal erfolgen. Es ist allerdings so, dass scheinbar mehrere Threads erstellt werden und so der CurrentPrincipal nicht erhalten bleibt. Eine Lösung ist, den Benutzer für die aktuelle Domäne der Anwendung zu setzen – also mit AppDomain.CurrentDomain.SetThreadPrincipal(principal).

Ich hoffe das kann dem einen oder anderen helfen.

KategorienProgrammierung Tags: , , ,

Fehler in der Fensterbehandlung von WPF

2. Oktober 2009 Keine Kommentare

Gerade habe ich einen kleinen Fehler in WPF entdeckt. Scheinbar ist es so, dass Fensterinstanzen bei der Instanziierung schon zur WindowCollection hinzugefügt werden und nicht erst wenn Sie geöffnet werden. Dadurch muss man Sie erst entfernen, bevor man das Programm beenden kann, da es ansonsten denkt, dass noch ein Fenster offen ist.

Mehr…

KategorienProgrammierung Tags: ,

Maskedtextbox in WPF implementieren

29. Juli 2009 1 Kommentar

Heute beschreibe ich mal, wie man in WPF ein Control erstellt, dass von TextBox erbt und die Funktionalität einer Maskedtextbox bietet. Als ich vor kurzem diese Funktionalität brauchte hat sich herausgestellt, dass das ganze innerhalb von kurzer Zeit erledigt werden kann.

Mehr…

ConnectionString für SQL Server CE zum Zugriff auf eine Netzwerkfreigabe

5. Oktober 2008 Keine Kommentare

Ich arbeite gerade an einem kleinen Tool dass auf dem SQL Server CE basiert. Dabei soll auf eine Datei zugegriffen werden, die auf einer Netzwerkfreigabe liegt, welche nicht als Laufwerk eingebunden ist. Mit dem generierten Connectionstring funktioniert dies leider nicht, aber endlich habe ich die Lösung gefunden:

Mehr…

KategorienProgrammierung Tags: ,

Automatische Höhe für Labels im Compact Framework auf dem Pocket PC

27. Mai 2008 Keine Kommentare

Für ein kleines Projekt für Windows CE habe ich eine Methode gesucht um die Höhe eines Labels anhand des Inhalts automatisch zu setzen. Dabei habe ich hier eine Lösung in Visual Basic gefunden. Diese Lösung ist eigentlich recht elegant, da Sie API-Funktionen benutzt um das Rectangle zu zeichnen und die Höhe genau so zu bestimmen wie Sie auch später im Formular erscheinen würde wenn man z.B. den Text in ein Textfeld schreiben würde.

Hier eine Übersetzung in C#: Mehr…

Registerkarte zum Outlook Optionen-Dialog hinzufügen

9. April 2008 7 Kommentare

Nachdem ich jetzt ca. 1 Std. gebraucht habe um herauszufinden wie es geht beschreibe ich das einfache Verfahren.

Mehr…

WMI-Informationen mit C# auslesen

21. März 2008 Keine Kommentare

Ich brauchte für den MAC-Switcher eine einfache Möglichkeit den Namen der Netzwerkverbindungen wie er in der Systemsteuerung angezeigt wird auszulesen. Mit Hilfe von WMI ist dies unglaublich einfach.

Mehr…