Dotlab – Development and other evil things


Lokalisierung mit Cultures

Veröffentlicht in .net Stuff von dotlab am März 3, 2008
Tags: , , ,

Um ein .Net Webprojekt zu lokalisieren, wurden bis anhin bei uns sämtliche Elemente in separaten Strings übersetzt gehalten und zur Laufzeit mittels Select/Case (abhängig von der ausgewählten Sprache) ausgelesen und den Objekten zugeordnet. Ein Relikt aus alten Projekten..

Dass dies auch eleganter geht, zeigt das folgende Beispiel. Nachdem eine .aspx Seite aufgebaut wurde (inkl. Code-behind File), kann in Visual Studio 2005 unter „Tools“ der Punkt „Generate Local Resource“ ausgewählt werden. Es wird automatisch im Projekt ein Ordner App_LocalResources angelegt mit dem Namen der Webform und dem Zusatz .apsx.resx. In dem File finden sich sämtliche verwendeten Elemente der .aspx Seite wieder, zu jedem Element existiert ein String mit dem angezeigten Text. Die Liste kann manuell beliebig erweitert werden, falls neue Buttons oder was auch immer zur Seite hinzugefügt werden. Nun kann das .resx File kopiert und umbenannt werden, beispielsweise „Default.aspx.de-CH.resx“ oder „Default.aspx.en-US.resx“. Der Filenamen enthält nun bereits die Sprachspezifikation. Die einzelnen Strings in den Files können bequem übersetzt werden, Visual Studio stellt dafür einen kleinen Editor zur Verfügung.

Zur Laufzeit kann nun innerhalb der Webform „CurrentCulture“ und „CurrentUICulture“ gesetzt werden, aufgrund dieser Auswahl wird das entsprechende .resx File eingelesen und die Strings automatisch auf die Objekte gemappt. Natürlich können die Strings aber auch manuell ausgelesen werden. Hier ein Codesample:


using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Threading;
using System.Globalization;

public partial class _Default : System.Web.UI.Page
{
    // Methode um manuell ein ResouceObject auszulesen
 public string G(string sKey)
 {
 	return GetLocalResourceObject(sKey).ToString(); ;
 }

    // Init
 protected override void InitializeCulture()
 {
 	base.InitializeCulture();
 	string selectedLanguage = "de-CH";//""en-US";
 	Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(selectedLanguage);
 	Thread.CurrentThread.CurrentUICulture = new CultureInfo(selectedLanguage);
 }

    // Einem ASP Button einen String manuell zuweisen
   protected void Page_Load(object sender, EventArgs e)
 {
    Button1.Text = G("Button1Resource1.Text");
 }
}

Parameter an Telerik DockableObject Form mit Reflection übergeben

Veröffentlicht in .net Stuff von dotlab am Februar 27, 2008
Tags: , , , ,

Eine kleine Knacknuss hat sich bei der Verwendung der Telerik Docking Zones (DZ) rsp. Dockable Objects (DO) ergeben. Folgende Situation: drei DZ liegen nebeneinander, alle werden dynamisch mit DO gefüllt. Als ContentTemplate wird für jedes DO ein eigenes Control definiert, welches nach dem Aufklappen des DO eine umfangreiche Editmaske zur Verfügung stellt. Soweit so gut, bloss muss dem Control innerhalb des DO ein Parameter übergeben werden, damit dort die ID des DO zur Verfügung steht. Alles klar? :-)

Der erste Versuch nur über ein Property war nicht von Erfolg gekrönt. Die Lösung heisst: Reflection! Hier ein Vorschlag, wie die Create Methode aussehen könnte:

Function CreateDockableObject(ByVal _Id As Integer, ByVal _Text As String) As RadDockableObject
            'create new dockable object
            Dim dObj As New RadDockableObject
            dObj.ID = _Id
            dObj.Text = _Text
            dObj.DockingMode = RadDockingModeFlags.AlwaysDock
            dObj.Expanded = False
            dObj.Width = "250"

            'load a user control as a template
            Dim myUC As UserControl
            myUC = CType(LoadControl("Controls/ModulEdit.ascx"), UserControl)
            Dim ucType As Type = myUC.GetType()

            'pass a parameter to the user control
            Dim ucProperty As Reflection.PropertyInfo = ucType.GetProperty("mId")
            ucProperty.SetValue(myUC, _Id, Nothing)

            'add user control to dockable object template
            dObj.ContentTemplate = myUC
            Return dObj

        End Function

Natürlich muss im Control ein entsprechendes Property (hier „mId“) vorhanden sein. Ist dies der Fall, funktioniert alles bestens!

Arbeiten mit Verzeichnissen in vb.net

Veröffentlicht in .net Stuff von dotlab am Februar 15, 2008
Tags: , , ,

Zu internen Zwecken musste ich ein kleines Tool schreiben, welches diverse Verzeichnisse abgleicht und ein paar Fileoperationen ausführt. Dafür gibt’s in .net eine praktische Lösung! Mit dem folgenden Code kann für jede Datei in einem Verzeichnis eine Aktion ausgeführt werden.

Imports System.IO
Imports System.Data

Partial Public Class _Default
Inherits System.Web.UI.Page

Dim SourcePath As String = "C:\Test\TestSource"

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

Dim di As New DirectoryInfo(SourcePath)
For Each fi As FileInfo In di.GetFiles

Dim mySourceFilename As String = fi.Name

'do something

Next

End Sub

Fortune Cookie Codes mit .net

Veröffentlicht in .net Stuff von dotlab am Februar 14, 2008
Tags: , ,

Für einen Kunden sollten wir einen Glückscode-Generator schreiben. Die Anforderungen waren relativ simpel: Codes im Format xxxx-xxxx-xxxx, natürlich absolut unique Codes, performant auch bei der Erzeugung von mehreren 100′000 Codes im Zusammenspiel mit einer MS SQL Datenbank.Zur Erzeugung der Codes verwendeten wir die .net GUID (globally unique identifier) Funktion, die diese Arbeit recht hübsch erledigt. In einer For-Next Schlaufe werden die Codes generiert, transformiert und in eine Datatable geschrieben. Die Funktion DeleteDuplicates erstellt einen DataView, sortiert diesen nach Codes und arbeitet sich top-down. Sind zwei aufeinanderfolgende Codes identisch, wird der aktuelle gelöscht. Fertig ist die Geschichte, das Ganze wird in diesem Beispiel in ein XML File gespeichert.Werden die Codes in eine SQL Db gespeichert, kann die Einzigartigkeit zusätzlich überprüft werden mit einer DISTINCT Abfrage.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

‘number of codes to generate
Dim EndCount As Integer = 5000

‘create the datatable and add a row
objDT = New System.Data.DataTable(”CodeTable”)
objDT.Columns.Add(”Code”, GetType(String))

‘create random id, transform code
Dim count As Integer
For count = 0 To EndCount - 1

‘edit the string
Dim myCode As String = Guid.NewGuid.ToString

‘add some separators and cut the string down on 15 chars (3 x 4chars + 3x 1 separator)
myCode = UCase(myCode.Replace(”-”, “”))
myCode = myCode.Insert(4, “-”)
myCode = myCode.Insert(9, “-”)
myCode = myCode.Substring(0, 14)

‘add to datatable
objDR = objDT.NewRow
objDR(”Code”) = myCode.ToString
objDT.Rows.Add(objDR)

Next

’start the sub
DeleteDuplicates(objDT)

‘Serialize the datatable object into a xml file
objDT.WriteXml(”final_codes.xml”)
objDT.WriteXmlSchema(”final_scheme.xslt”)

‘output the number of generated codes
lblNumRows.Text = objDT.Rows.Count & ” Codes generiert”

End Sub

‘Selects duplicate entries and removes them
Public Sub DeleteDuplicates(ByVal dt As DataTable)
Dim myDataView As New DataView(dt)
myDataView.Sort = “Code”
For x As Integer = 0 To myDataView.Count - 2
Dim myDataRowView As DataRowView = myDataView.Item(x)
Dim myDataRowViewNext As DataRowView = myDataView.Item(x + 1)
If myDataRowView.Item(”Code”).ToString = myDataRowViewNext.Item(”Code”).ToString Then
myDataRowView.Delete()
End If
Next
End Sub

End Class