Glengamoi (Forum) · AspHeute · .NET Heute (RSS-Suche) · AspxFiles (Wiki) · .NET Blogs
ASP German Homepage Homepage
 

Liste

.NET 2.0 (1)
.NET Allgemein (16)
.NET Fu (5)
ADO.NET (11)
Aprilscherz (3)
ASP Grundlagen (44)
ASP Tricks (83)
ASP.NET (44)
ASPIntranet.de (5)
C# (28)
Datenbank (44)
Dokumentation (4)
IIS 6.0 (1)
Komponenten (29)
Optimierung (10)
Server (21)
Sicherheit (34)
Tee Off (6)
VB.NET (6)
WAP (8)
Web Services (11)
XML (9)

RSS 2.0 - Die neuesten fünf Artikel auf AspHeute.com


 

Suchen





 

English Articles
Chinese Articles
Unsere Autoren
 
Link zu AspHeute
Impressum
Werben
Anfragen

Zahl, Datum und Währung korrekt formatiert ausgeben

Geschrieben von: Christoph Wille
Kategorie: .NET Allgemein

Ein wenig geliebtes Thema unter ASP war das Formatieren von Zahlen passend zu länderspezifischen Einstellungen - meist schummelten sich die Programmierer darüber hinweg, mit dem Ergebnis, daß wenn man von einem deutschen Webserver auf einen englischen migrierte, nichts mehr korrekt ausgegeben wurde. Unter .NET gibt es keine Ausreden mehr, seine Applikationen von vorne herein global auszulegen: Internationalisierung hat seinen Schrecken verloren.

Wir beschäftigen uns heute mit der landesspezifisch korrekt formatierten Ausgabe von Zahlenwerten, Währungswerten und Datumswerten. Die vorgestellten Techniken sind aber auch auf andere Internationalisierungsprobleme anwendbar, so zB das kulturell korrekte vergleichen von Zeichenketten. Übrigens: die heute vorgestellten Beispiele sind in ASP.NET programmiert - die vorgestellten Techniken sind 1:1 auch in allen anderen .NET Applikationen einsetzbar.

Formatieren mit der CurrentCulture des Threads

Die einfachste Variante ist, die Eigenschaft CurrentCulture des Threads, auf dem der Code läuft, umzusetzen. Diese Variante hat einen großen Vorteil: es ist nur eine Zeile Code notwendig, und alle nachfolgenden Aufrufe bedienen sich ab dann der neuen Einstellungen aus dem CultureInfo Objekt. Der folgende Code aus FormatOne.aspx demonstriert die Vorgehensweise:

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Globalization" %>
<%@ Import Namespace="System.Threading" %>
<html>
<head>
    <title>Simple Formatting</title>
</head>
<body>
<%
// Testwerte
DateTime dtVal = DateTime.Now;
double dVal = 37068.89;

// Ausgabe auf Default-Culture
Response.Write(dtVal.ToString() + "<br>");
Response.Write(dVal.ToString() + "<br><br>");

// Umstellen des Threads auf Deutsch
CultureInfo ciCurrent = new CultureInfo("de-DE");
Thread.CurrentThread.CurrentCulture = ciCurrent;

// Ausgabe in deutschem Format
Response.Write(dtVal.ToString() + "<br>");
Response.Write(dVal.ToString() + "<br>");
%>
</body>
</html>

Um diese Technik einzusetzen, müssen Sie die Namespaces System.Globalization (für die CultureInfo Klasse) und System.Threading (für das Thread Objekt) einbinden. Zuerst gibt das Programm einen Zahlenwert und ein Datum nach den aktuellen Einstellungen aus, danach stellen wir die CultureInfo des Threads auf Deutsch/Deutschland um:

CultureInfo ciCurrent = new CultureInfo("de-DE");
Thread.CurrentThread.CurrentCulture = ciCurrent;

Damit laufen wir ab sofort mit deutschen Einstellungen, und obwohl ich nichts am Ausgabecode geändert habe, bekomme ich nun korrekt deutsch formatierte Werte (die zweiten zwei Zeilen):

7/3/2002 6:30:09 PM
37068.89

03.07.2002 18:30:09
37068,89

Wie man an den ersten beiden Zeilen sieht, ist mein Server auf US Englisch eingestellt. Das macht aber nun nichts mehr, da ich jederzeit die CultureInfo ändern kann. Jederzeit beliebig umschalten, je nach dem, welche Einstellungen man gerade braucht.

Formatieren mit IFormatProvider Overloads

Hin und wieder ist das Umstellen des ganzen Threads auf eine andere CultureInfo nicht gewünscht (zB ein Chatserver der mehrsprachige Chaträume bedient). Hier will man sich darauf beschränken, nur die jeweilige Formatierungsoperation mit anderen Einstellungen durchzuführen. Dafür gibt es bei zB ToString oder String.Format Overloads, die ein Interface des Typs IFormatProvider annehmen, mit dem dann die Ausgabe kulturspezifisch gemacht wird.

Wie kommt man an ein solches Interface heran? Sehr einfach: die CultureInfo Klasse implementiert es. Die Probe aufs Exempel liefert FormatTwo.aspx:

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Globalization" %>
<html>
<head>
    <title>Simple Formatting, 2</title>
</head>
<body>
<%
// Testwerte
DateTime dtVal = DateTime.Now;
double dVal = 37068.89;

CultureInfo ciGermany = new CultureInfo("de-DE");
Response.Write(dtVal.ToString(ciGermany) + "<br>");
Response.Write(dVal.ToString(ciGermany) + "<br><br>");


CultureInfo ciCdnFrench = new CultureInfo("fr-CA");
Response.Write(String.Format(ciCdnFrench, "{0} {1}", dtVal, dVal));
%>
</body>
</html>

Ich erspare mir einen Namespace-Import, und auch das zentrale umschalten der CurrentThread.CultureInfo. Ich muß nur das CultureInfo Objekt an die entsprechenden Methoden übergeben (ToString und Format). Nicht nur die Formatierung kann man auf diese Art und Weise bewerkstelligen, auch Stringvergleiche laufen nach diesem Schema ab.

Ein Culture Browser

Damit Sie ein kleines Tool zum Experimentieren haben, erstellen wir ein ASP.NET Formular, mit dem Sie die verschiedenen CultureInfo's austesten können. Fertig sieht das Tool so aus:

In der linken Listbox werden die neutralen Cultures dargestellt (CultureTypes.NeutralCultures). Die rechte Listbox wird nach Selektionsänderung links mit den Unterkategorien der neutralen Culture befüllt (CultureTypes.SpecificCultures). Wird dann eine spezielle Culture ausgewählt, zeigen wir unter den Listboxen Beispiele an, wie sie für diese CultureInfo typisch sind.

Als Tool zur Erstellung dieses Web Forms habe ich das ASP.NET Web Matrix Projekt verwendet. Der erste Schritt ist eine neue ASPX Datei anzulegen:

Danach fügen wir die linke Listbox ein (Drag and Drop), und geben dieser den Namen lbNeutralCultures. Diese müssen wir mit den neutralen Cultures befüllen, und dies passiert am besten im Load Event der Seite (siehe Screenshot - im Load Event doppelklicken):

Damit sind wir in der Codeansicht. Geben Sie folgenden Code im Load Event ein:

    void Page_Load(Object sender, EventArgs e)
    {
     if (!Page.IsPostBack)
     {
    
        CultureInfo[] aCIs = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
        for (int i=0; i < aCIs.Length; i++)
        {
            lbNeutralCultures.Items.Add(new ListItem(aCIs[i].EnglishName + " [" + aCIs[i].Name + "]",
                                        aCIs[i].Name));
        }
     }
    }

Die statische Methode GetCultures liefert uns ein Array von CultureInfo Objekten. Die so erhaltenen Werte tragen wir in die Listbox ein. Der Value der Listbox wird für das neuerliche Erzeugen des CultureInfo Objekts verwendet, nämlich dann, wenn der User einen anderen Wert in der Listbox auswählt.

Die Auswahl eines neuen Wertes triggert das SelectedIndexChanged Event. Wählen Sie zuerst aber an, daß die Listbox ein AutoPostback auslöst, weil sonst passiert nämlich gar nichts! Der Code für das Event sieht so aus (lbSpecificCultures ist die zweite Listbox, lblInfo der Beispieltext der ausgegeben wird):

    void lbNeutralCultures_SelectedIndexChanged(Object sender, EventArgs e)
    {
        lbSpecificCultures.Items.Clear();
        lblInfo.Text = "";
    
        CultureInfo ciCurrent = new CultureInfo(lbNeutralCultures.SelectedItem.Value);
    
        CultureInfo[] aCIs = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
    
        for (int i=0; i < aCIs.Length; i++)
        {
            if (ciCurrent.Equals(aCIs[i].Parent))
            {
                ListItem li = new ListItem(aCIs[i].EnglishName + " [" + aCIs[i].Name + "]",
                                           aCIs[i].Name));				
                lbSpecificCultures.Items.Add(li);
            }
        }
    }

Der etwas umständliche Teil hier ist, daß man für eine neutrale Culture sich nicht alle spezifischen Cultures auflisten lassen kann. Man muß sich alle spezifischen holen, und dann mit ciNeutral.Equals(ciSpecific.Parent) herausfinden, ob denn die spezifische Culture ein Kind der neutralen ist. Weniger cool, aber that's life.

Der letzte Schritt ist, die Beispiele nach Culture formatiert anzuzeigen. Dies passiert nachdem der User in der rechten Listbox die Auswahl geändert hat. Also auf der Listbox lbSpecificCultures AutoPostback auf True setzen, und das SelectedIndexChanged Event implementieren:

    void lbSpecificCultures_SelectedIndexChanged(Object sender, EventArgs e)
    {
        StringBuilder strInfo = new StringBuilder();
    
        CultureInfo ciCurrent = new CultureInfo(lbSpecificCultures.SelectedItem.Value);
    
        if (!ciCurrent.IsNeutralCulture)
        {
            Thread.CurrentThread.CurrentCulture = ciCurrent;
            strInfo.Append("Kurzes Datum: ");
            strInfo.Append(DateTime.Now.ToShortDateString());
            strInfo.Append("<br>Langes Datum: ");
            strInfo.Append(DateTime.Now.ToLongDateString());
            strInfo.Append("<br>Kurze Zeit: ");
            strInfo.Append(DateTime.Now.ToShortTimeString());
            strInfo.Append("<br>Lange Zeit: ");
            strInfo.Append(DateTime.Now.ToLongTimeString());
            strInfo.Append("<br>Zahl (35007.09): ");
            strInfo.Append((35007.09).ToString("n"));
            strInfo.Append("<br>Währung (1057.80): ");
            strInfo.Append((1057.80).ToString("c"));
        }
    
        lblInfo.Text = strInfo.ToString();
    }

Damit hat man den Culture Browser fertig, und kann sich "live" die Unterschiede der einzelnen Cultures ansehen, in Bezug auf Datums-, Zahlen- und Währungswerte. So auf auch chinesisch (wenn man die Schriften installiert hat):

Schlußbemerkung

Das Formatieren von Werten in Bezug auf eine spezielle Culture ist mit .NET extrem vereinfacht worden, man muß keine Winkelzüge mehr machen. Und ein weiterer Vorteil: das Wissen um Internationalisierung muß man sich nur einmal aneignen, man kann es in allen .NET Anwendungen einsetzen.

Download des Codes

Klicken Sie hier, um den Download zu starten.

Verwandte Artikel

@-Direktiven auf ASP Seiten
Das ASP.NET Web Matrix Projekt
Die String Klasse in C#
Einführung in ASP.NET Web Forms
Einträge numerieren im DataGrid
Eventbehandlung bei ASP.NET WebForms
Fernöstliche Formulare / Unicode die Zweite
Pager- und Footerzeilen des DataGrid erweitern
Unicode und ASP (Einführung)
Wochenberechnung mit .NET

Wenn Sie jetzt Fragen haben...

Wenn Sie Fragen rund um die in diesem Artikel vorgestellte Technologie haben, dann schauen Sie einfach bei uns in den Community Foren der deutschen .NET Community vorbei. Die Teilnehmer helfen Ihnen gerne, wenn Sie sich zur im Artikel vorgestellten Technologie weiterbilden möchten.

Eine weitere sehr hilfreiche Resource ist das deutsche ASP.NET Wiki, das als zentrale Anlaufstelle für Tips, Tricks, Know How und alles Nützliche was man in seinem Alltag als (ASP).NET-Entwickler so braucht und entdeckt gedacht ist.

Haben Sie Fragen die sich direkt auf den Inhalt des Artikels beziehen, dann schreiben Sie dem Autor! Unsere Autoren freuen sich über Feedback zu ihren Artikeln. Ein einfacher Klick auf die Autor kontaktieren Schaltfläche (weiter unten) und schon haben Sie ein für diesen Artikel personalisiertes Anfrageformular.

 

Und zu guter Letzt möchten wir Sie bitten, den Artikel zu bewerten. Damit helfen Sie uns, die Qualität der Artikel zu verbessern - und anderen Lesern bei der Auswahl der Artikel, die sie lesen sollten.

Bewerten Sie diesen Artikel
 Sehr gut   Nicht genügend  
   1  2  3  4  5  
 

  
   Für Ausdruck optimierte Seite

©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.