Blog Home  Home Feed your aggregator (RSS 2.0)  
HP's Blog - Tuesday, January 05, 2010
Hans-Peter Schelian's Weblog
 
# Tuesday, January 05, 2010

Eigentlich wurde ja bereits mit der Version 5.0 erwartet, dass DotNetNuke nun endlich mehr Internationalität erhält.

Dem war aber nicht so, und mit der Version 5.0 wurden keinen echten Schritte in die Richtung Mehrsprachigkeit gegangen.

Mit der Version 5.2 beginnt nun aber tatsächlich der erste große Schritt in “diese Richtung” ich wollte eigentlich “richtige Richtung” schreiben, aber da bin ich mir noch nicht sicher, warten wir es ab. Leider, oder wie ich sagen würde, wie erwartet, geschieht dies nicht ohne das es dabei zu gravierenden Änderungen (Breaking Changes) in der Datenbankstruktur kommt.

Mit der Version 5.2.0 wird nun folgende gravierende Änderung vollzogen:

Die Tabelle Portals wird International.

Alle Informationen der Tabelle welche Lokalisierbar sein müssen wurden, in eine neue Tabelle PortalLocalization verschoben und alle Einstellungen aus der Tabelle wurden zusammen mit einem Sprachcode in die Portalsettings Tabelle verschoben.

Das ganze führt bei einigen Programmen (Beispielsweise sei hier das Document Exchange Module von Bring2Mind genannt) dazu, dass diese nicht mehr ohne Update mit DNN 5.2.X und höher betrieben werden können.

Sollte ein eigenes Modul von einer solchen Änderung betroffen sein, so sollte man sich die ebenfalls neuen Views (ja DNN verwendet nun auch Views)

  • vw_Portals (Alle Sprachen)
  • vw_PortalsDefaultLanguage (Standard Sprache entspricht der Lösung vor DNN 5.2)

ansehen.

Durch Verwendung einer dieser Views kann man durch einfache Änderung des Zugriffs von der Portals Tabelle auf eine dieser Views die notwendigen Informationen für sein Modul erhalten, ohne gleich die gesamte Lokalisierungsfunktionalität zu implementieren.

Fortsetzung folgt!!!

DotNetNuke | Entwicklung
Tuesday, January 05, 2010 12:11:00 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Wednesday, December 30, 2009

Vor kurzem wurde im Zuge eines Projektes  (Unterstützung eines Entwickler Teams für eine Winform Anwendung im Logistikumfeld) unter anderem die Anforderung an mich heran getragen, dass der Kunde die Ansprechpartner für eine bestimmte Logistische Aktivität aus einer Combobox auswählen möchte.

Hierbei sollte in der Combobox, nicht nur ein Feld aus der Datenbank angezeigt werden, sondern die Anzeige sollte aus insgesamt 2 Feldern zusammengebaut werden.

Das Format sollte so aussehen: Nachname, Vorname

Hier ein Beispiel:

Mustermann, Hans

Dabei sollte die Lösung vollkommen im Client implementiert sein und nicht durch eine geänderte Abfrage der Datenbank realisiert werden.

Nun ist es aber so, dass man dem DisplayMember nur ein Feld der Datengebundenen Tabelle (Objekt) zuweisen kann und nicht mehrere oder sogar wie hier gewünscht diese Felder auch noch in einem bestimmten Format.

Sicherlich könnte man sich ein eigenen Objekt (List Objekt) erzeugen welches man dann als Datenquelle für die Bindung verwendet, aber es geht auch (viel) einfacher.

Hierzu verwenden wir dem Format Event der Combobox.

Dieser Event bekommt zwei Parameter mit übergeben:

object sender

ListControlConvertEventArgs e

Wobei wir für die hier beschriebene Lösung lediglich den ListControlConvertEventArgs Parameter benötigen und auch verwenden.

in e.ListItem wird das Datengebundene Objekt übergeben und in e.Value kann man den gewünschten Wert zurückgeben.

Hier ein zusammenhängendes Beispiel:

private void cmbSpediteurKontakt_Format(object sender, ListControlConvertEventArgs e)
{
	// Hier caste ich mir den übergeben Wert in das original Objekt
	var spediteurKontakt = ((SpediteureKontakte) e.ListItem);  
	// Und nun bastele ich mir die gewünschet Anzeige zusammen
	e.Value = String.Format("{0}, {1}", spediteurKontakt.Nachname, spediteurKontakt.Vorname);
}

Und das Ergebnis sieht dann so aus:

image

Tips und Tricks | C#
Wednesday, December 30, 2009 3:07:00 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Wednesday, November 25, 2009

Seit Heute Morgen ist der erste Release Kandidat der neuen 3.0 Version von Thunderbird verfügbar.

Einen direkten Link zum herunterladen konnte ich zwar nicht finden, aber wer die Beta 4 auf einem Rechner hat, kann mit dem “Auf Update prüfen” seine Version aktualisieren.

Auf dieser Seite finden man die Links zu den Downloads.

Kurz und Bündig | Thunderbird
Wednesday, November 25, 2009 7:29:08 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Tuesday, October 27, 2009

Seit ein paar Wochen habe ich eine Logitech MX 3200 Laser Tastatur / Maus Kombination im Einsatz.

Außer der störenden Zoomfunktion am linken Rand bin ich auch sehr zufrieden.

Verzweifelt habe ich nach einer Lösung gesucht diese Zoom Funktion zu deaktivieren und habe nichts gefunden.

Heute bin ich dann durch Zufall auf die Lösung gestoßen.

Hier der Link zur Web Seite mit der Lösung

Besten Dank an Cord-Heinrich Pahlmann

Tips und Tricks
Tuesday, October 27, 2009 3:05:00 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Tuesday, September 29, 2009

In einer Windows Anwendung wird in einer Form unter anderem ein (eigentlich sind es zwei, aber dazu später mehr) DateTimePicker verwendet um Termine einzugeben.

Da der DateTimePicker nicht gerade komfortabel ist um sowohl Datum als auch Uhrzeiten einzugeben, wird ein DateTimePicker in der Option DropDownCalender (das ist deaktivierte Eigenschaft ShowUpDown) eingesetzt um das Datum elegant aus dem DropDownCalender auszuwählen und ein zweites DateTimePicker Control mit der gesetzen Eigenschaft ShowUpDown und dem entsprechenden Custom Format HH:mm um nur die Uhrzeit mit den Pfeilen hoch und runter einstellen zu können.

image

Nun ist es aber so, dass man im DateTimePicker keinen Inkrement Wert eingeben kann, um den die Minuten erhöht bzw vermindert werden wenn man einmal auf den Pfeil hoch oder runter klickt. Somit wird jeweils um eine Minute hoch oder runter gezählt.

In meinem Fall nun wollte der Kunde aber das Termine nicht Minutengenau sondern immer auf 15 Minuten (Viertelstunde) Basis, also 00, 15, 30 und 45 erfasst werden können.

Da ich nicht gleich ein eigenen Control entwickeln wollte, habe ich einfach eine kleine Routine in den Change Event des DateTimePicker eingebaut.

Nachfolgend der Code Ich denke die Routine ist selbsterklärend

private void startzeitTimePicker_ValueChanged(object sender, EventArgs e)
{
    DateTimePicker dtp = (DateTimePicker)sender;
    // Wenn nicht Minute nicht 0,15,45 oder 60 dann müssen wir was tun
    if ((((dtp.Value.Minute != 0) && (dtp.Value.Minute != 15)) && (dtp.Value.Minute != 30)) &&
        (dtp.Value.Minute != 45))
    {
        // Auch noch einfach, nur 14 Minuten drauf und gut ist
        if ((dtp.Value.Minute == 1) || (dtp.Value.Minute == 16) || (dtp.Value.Minute == 31) || (dtp.Value.Minute == 46))
        {
            dtp.Value = dtp.Value.AddMinutes(14);
        }
        else
        {
            // Zeit wurde heruntergezählt.
            if ((dtp.Value.Minute == 14) || (dtp.Value.Minute == 29) || (dtp.Value.Minute == 44) || (dtp.Value.Minute == 59))
            {
                int x = 14;     // Deshalb auf jeden Fall mal 14 Minuten abziehen,
                if (dtp.Value.Minute == 59)  // und wenn die Minuten auf 59 stehen, dann muss noch eine Stunde (60 minuten) mehr abgezogen werden
                {
                    x += 60;
                }
                dtp.Value = dtp.Value.AddMinutes(-x);
            }
            else // Wert muss manuell eingegeben worden sein, dann runden wir auf die nächst höhere Viertelstunde
            {
                for (int i = 0; i < 15; i++)
                {
                    int x = dtp.Value.Minute + i;
                    if ((x == 15) || (x == 30) || (x == 45) || (x == 60))
                    {
                        dtp.Value = dtp.Value.AddMinutes(i);
                        break;
                    }
                }
            }
        }
    }
}

Hoffe das hilft dem einen oder anderen (Oder mir selbst beim nächsten mal wenn ich vor dem gleichen Problem stehen Wink)

Code | Tips und Tricks | C#
Tuesday, September 29, 2009 12:39:00 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Friday, August 07, 2009

In einer Anwendung verwende ich eine Klasse um die Appointmens eines Kalenders abzubilden. Diese Klasse ist relativ Komplex und um diesen Beitrag nicht ebenfalls zu komplex werden zu lassen, verwende ich hier eine (sehr) abgespeckte Version dieser Klasse um das Thema Sortierung einer ArrayListe von Komplexen Objekten zu veranschaulichen.
Die Verwendung einer ArrayList war hier zwingend vorgeschrieben (typisierte Listen List<Type> kamen nicht in Frage)

Zuerst einmal die Aufgabenstellung:

In einer ArrayListe (nennen wir Sie AppointmentList) befinden sich Termine in Form von Objekten (nennen wir sie Appointment). Diese Objekte haben unter anderem eine Eigenschaft (Property) Startdatum (vom Type DateTime).

Da die Appointment in der AppointmentList unsortiert vorliegen und eine Sortierung (eigentlich zwei Sortierungen Auf und Absteigend) nach dem Startdatum des Termins benötigt wird, bestand die Aufgabe die AppointmentList zu sortieren.

Die ArrayLIst verfügt über eine Methode Sort. Da es sich bei den zu sortierenden Objekten aber um ein Komplexe Klasse handelt, muss man der Sort Methode einen Comparer an die Hand geben, damit die Methode Sort Ihre Aufgabe durchführen kann.

Hier nun die Umsetzung:

Zuerst einmal die (komplexe) Klasse Appointment (eine abgespeckte Variante)

public class Appointment
{

    public Appointment()
    {
        appointmentGUID = Guid.NewGuid();
    }


    private readonly Guid appointmentGUID = new Guid("00000000000000000000000000000000");

    public Guid AppointmentGUID
    {
        get { return appointmentGUID; }
    }

    private DateTime startDate;

    public DateTime StartDate
    {
        get { return startDate; }
        set
        {
            startDate = value;
            OnStartDateChanged();
        }
    }

    protected virtual void OnStartDateChanged()
    {
    }


    private DateTime endDate;

    public DateTime EndDate
    {
        get { return endDate; }
        set
        {
            endDate = value;
            OnEndDateChanged();
        }
    }

    protected virtual void OnEndDateChanged()
    {
    }



    private string title = "";

    [DefaultValue("")]
    public string Title
    {
        get { return title; }
        set
        {
            title = value;
            OnTitleChanged();
        }
    }

    protected virtual void OnTitleChanged()
    {
    }


    public override string ToString()
    {
        return Title;
    }

}

Der Comparer für diese Aufgabe sieht dann so aus (Methode zum Sortieren mit Implementierung der IComparer Schnittstelle:

public class AppointmentComparer : IComparer
{
    private bool descendSorting;
    public AppointmentComparer(bool descend)
    {
        descendSorting = descend;
    }

    int IComparer.Compare(object a, object b)
    {
        var b1 = (Appointment)a;
        var b2 = (Appointment)b;

        if (descendSorting)
        {
            return DateTime.Compare(b2.StartDate, b1.StartDate);
        }
        else
        {
            return DateTime.Compare(b1.StartDate, b2.StartDate);
        }
    }

}

Und verwenden kann man diesen Comparer wie folgt:

            al.Sort(new AppointmentComparer(false));
            al.Sort(new AppointmentComparer(true));

al wurde dabei wie folgt deklariert:

ArrayList al = new ArrayList();
Code | C#
Friday, August 07, 2009 1:14:00 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Wednesday, August 05, 2009

Beim stöbern in meinen SQL Skripten bin ich gerade wieder auf das hier nachfolgend aufgeführte Skript zur Ausgabe der “Größe aller Tabellen einer Datenbank” gestoßen.

Da ich sicherlich nicht der einzige bin, der diese Informationen einer Datenbank hin und wieder benötigt, veröffentliche ich hier das Skript mit der Hoffnung dass es jemand gebrauchen kann.

SET NOCOUNT ON
CREATE TABLE #TableSpace 
(
	Rows int, 
	DataSpaceUsed int, 
	IndexSpaceUsed int
)
DECLARE @TableSpace table
(
	TableName varchar(255),
	Rows int, 
	DataSpaceUsed int, 
	IndexSpaceUsed int
)
DECLARE @Rows int, @DataSpaceUsed int, @IndexSpaceUsed int
DECLARE @TableName varchar(255)
DECLARE Table_Cursor CURSOR FOR
SELECT	user_name(o.uid) + '.' + o.name AS table_name
FROM	dbo.sysobjects o, dbo.sysindexes i 
WHERE	OBJECTPROPERTY(o.id, N'IsTable') = 1 
	AND i.id = o.id 
	AND i.indid < 2 
	AND o.name NOT LIKE N'#%' 
	AND xtype = 'U'
ORDER BY 1
OPEN Table_Cursor
---------------------------------
--Set Data
FETCH NEXT FROM Table_Cursor INTO @TableName
INSERT INTO #TableSpace (Rows, DataSpaceUsed, IndexSpaceUsed)
EXEC sp_MStablespace @TableName
SELECT	@Rows = Rows, 
	@DataSpaceUsed = DataSpaceUsed,
	@IndexSpaceUsed = IndexSpaceUsed
FROM	#TableSpace
INSERT INTO @TableSpace (TableName, Rows, DataSpaceUsed, IndexSpaceUsed)
VALUES (@TableName, @Rows, @DataSpaceUsed, @IndexSpaceUsed)
DELETE FROM #TableSpace
--------------------------------
WHILE @@FETCH_STATUS = 0


    BEGIN
    	---------------------------------
    	--Set Data
    	FETCH NEXT FROM Table_Cursor INTO @TableName
    	
    	INSERT INTO #TableSpace (Rows, DataSpaceUsed, IndexSpaceUsed)
    	EXEC sp_MStablespace @TableName
    	
    	SELECT	@Rows = Rows, 
    		@DataSpaceUsed = DataSpaceUsed,
    		@IndexSpaceUsed = IndexSpaceUsed
    	FROM	#TableSpace
    	
    	INSERT INTO @TableSpace (TableName, Rows, DataSpaceUsed, IndexSpaceUsed)
    	VALUES (@TableName, @Rows, @DataSpaceUsed, @IndexSpaceUsed)
    	
    	DELETE FROM #TableSpace
    	--------------------------------
END

CLOSE Table_Cursor
DEALLOCATE Table_Cursor
DROP TABLE #TableSpace
SELECT * 
FROM @TableSpace
ORDER BY Rows DESC

Über die Herkunft dieses Skripts (ich weiß dass ich zumindest die Idee von irgendwoher hatte) bin ich mir nicht mehr sicher. Eine gerade durchgeführte Recherche im Internet hat mir auch keinen direkten Aufschluss gegeben woher ich das Skript oder die Idee dazu hatte.

Sollte also jemand die Herkunft kennen, bitte einfach per Kommentar posten.

Tips und Tricks | SQL Server | SQL
Wednesday, August 05, 2009 9:26:38 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [5]  
Autor: Hans-Peter Schelian  |  Trackback
# Wednesday, July 22, 2009

Wenn man die Source Version von DotNetNuke Version 4.09.04 in Visual Studio ausführt und als Browser den Internet Explorer 8 einsetzt, kommt es beim überfahren der Menüs (Admin und Systemmenü) mit der Maus zu folgendem Fehler:

image

Dieser Fehler tritt in der Datei dnn.dom.positioning.js auf.

Die Zeile in welcher der Fehler auftritt lautet:

oIFR.style.zIndex=iIndex-1
Was geschieht ist, dass in der Variablen iIndex anstelle eines Wertes, das Wort “Auto” enthalten ist. Wenn nun versucht wird von dem String “Auto” den Wert 1 abzuziehen, kommt es natürlich zu einem Fehler.

Ich habe eine Lösung gefunden, die für mich funktioniert und nicht die Zeile einfach auskommentiert.

Die Lösung sieht wie folgt aus:

Ich füge am Ende der Datei dnn.dom.positioning.js die Funktion IsNumeric ein:

function IsNumeric(sText)

{
   var ValidChars = "0123456789.";
   var IsNumber=true;
   var Char;

 
   for (i = 0; i < sText.length && IsNumber == true; i++) 
      { 
      Char = sText.charAt(i); 
      if (ValidChars.indexOf(Char) == -1) 
         {
         IsNumber = false;
         }
      }
   return IsNumber;
   
   }

Und verwende diese Funktion wie folgt um den Inhalt der Variable iIndex zu prüfen und im Falle das darin kein numerischer Wert enthalten ist, führe ich die Subtraktion nicht aus.

Anstelle der Zeile (250) mit dem Inhalt oIFR.style.zIndex=iIndex-1;

füge ich nachfolgende 4 Zeilen ein, das sieht dann so aus:

if (IsNumeric(iIndex))
    oIFR.style.zIndex = iIndex - 1;
else
    oCont.style.zIndex = 1;

Nun einfach die Datei dnn.dom.positioning.js speichern und auch Fehlerfrei mit dem IE 8 und der Source Version von DotNetNuke arbeiten.

DotNetNuke | Entwicklung
Wednesday, July 22, 2009 8:52:05 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
Copyright © 2010 Hans-Peter Schelian - Schelian IT Beratung. All rights reserved.