Wer mal "eben" ein Regex-Pattern erstellen möchte und dieses auch direkt testen will, kann ein kleines Online-Tool dafür nutzen. Hier der Link
Ich kann es ja kaum glauben aber bei dem mächtigen Framework von .Net wird es echt kompliziert eine DateTime Wert von GMT in PST zu konvertieren. Habe gerade ein paar lustige Stunden damit verbraucht eine dieses einigermaßen sauber zu implementieren und hier meine Lösung:
Basis für meine Lösung ist eine Klasse von Clemens Vasters und seiner Blogengine dasblog.net. Dort gibt es im Projekt "newtelligence.DasBlog.Util.csproj" die Klasse "TimeZones.cs". Die nötigen Informationen für eine Konvertierung wird hier allerdings in einer XML Datei gespeichert. Da ich derzeit allerdings nur eine konvertierung nach PST brauch habe ich die XML Datei ignoriert und setze die Daten manuell in einer Klasse.
/// <summary> /// Liefert verschiedne Zeiten auf der Welt zurücl /// </summary> public class TimeZoneConverter {
/// <summary> /// (GMT-08:00) Pacific Time (US & Canada); Tijuana /// Pacific Daylight Time /// </summary> /// <returns>DateTime of Pacific Daylight Time</returns> public static DateTime GetCurrentPST() { return DateTime2PST(DateTime.Now) ; }
/// <summary> /// (GMT-08:00) Pacific Time (US & Canada); Tijuana /// Pacific Daylight Time /// </summary> /// <returns>DateTime of Pacific Daylight Time</returns> public static DateTime DateTime2PST(DateTime dtDate) {
WindowsTZI pstTZI = new WindowsTZI(); pstTZI.bias = 480; pstTZI.daylightBias = -60; pstTZI.standardBias = 0; WindowsSystemTime standardDate = new WindowsSystemTime(); standardDate.year = 0; standardDate.month = 10; standardDate.day = 5; standardDate.dayOfWeek = 0; standardDate.hour = 2; standardDate.minute = 0; standardDate.second = 0; standardDate.milliseconds = 0;
WindowsSystemTime daylightDate = new WindowsSystemTime(); daylightDate.year = 0; daylightDate.month = 4; daylightDate.day = 1; daylightDate.dayOfWeek = 0; daylightDate.hour = 2; daylightDate.minute = 0; daylightDate.second = 0; daylightDate.milliseconds = 0;
pstTZI.standardDate = standardDate; pstTZI.daylightDate = daylightDate;
WindowsTimeZone tz = new WindowsTimeZone(); tz.WinTZI = pstTZI; return tz.ToLocalTime ( dtDate.ToUniversalTime() ) ;
}
}
Wer das ganze etwas dynamischer haben möchte schaut sich am beste die Klasse vom Clemens an ...
Ich brauchte diese Funktion für die Google-Adwords-API, diese erwatet nämlich das Datum im PST Format.
Gerade habe ich einen interessanten Artikel gefunden der zeigt, wie man einen Parameter aus der Querystringauflistung entfernen kann.
Public Sub RemoveQueryString(ByVal Req As HttpRequest, ByVal strKeyToDel As String, ByVal http_Context As HttpContext) Dim nvc As System.Collections.Specialized.NameValueCollection = New System.Collections.Specialized.NameValueCollection(Req.QueryString) Dim sPage As String = Req.ServerVariables("SERVER_NAME") & Req.ServerVariables("SCRIPT_NAME") nvc.Remove(strKeyToDel)
Dim strNewURL As String = Req.Path Dim sSeparator As String = "?" Dim sKey As String For Each sKey In nvc If sKey <> Nothing Then Dim sValues As String() = nvc.GetValues(sKey) Dim sValue As String For Each sValue In sValues If sValue <> Nothing Then strNewURL &= sSeparator strNewURL &= sKey & "=" & sValue sSeparator = "&" End If Next End If Next If nvc.Keys.Count < 1 Then strNewURL &= "?" End If http_Context.Current.RewritePath(strNewURL) End Sub
Gefunden habe ich den Code unter http://www.codeproject.com
Eines meiner größten Probleme - oder sagen wir lieber Sorgen - war bisher, dass DNN keine Transaktionen unterstützt. Es gibt doch immer wieder mal Business-Cases wo man transaktionsicher Daten verarbeiten möchte. Ein typischens Beispiel wäre z.B. eine Online-Shop, wenn es um die Bestellung und gleichzeitige Zahlungsabwicklung geht.
Da DotNetNuke in vermutlich in vielen Fällen auf einem Windows 2003 Server betrieben wird, ist die komplette Umgebung schon vorhanden um die Abläufe transaktionssicher zu gestalten. Das Stichwort ist hier "Services without Components". Der Begriff "Services without Components" steht für die Nutzung von COM+-Dienste in .NET-Anwendung ohne Registrierung als Serviced Component (COM+-Anwendung).
Klassen: .ServiceConfig and System.EnterpriseServices.ServiceDomain
Das folgende Beispiel zeigt eine ganz einfache Implementierung innerhalb einer Methode:
//Hier wird mit einem Transaktionskontext gearbeitet, //damit das Handling einfacher wird ServiceConfig sc = new ServiceConfig(); sc.Transaction = TransactionOption.RequiresNew ; ServiceDomain.Enter ( sc ) ;
try { //mach was .... ContextUtil.SetComplete() ;
} catch (Exception exc) { ContextUtil.SetAbort() ; throw exc ; } finally { ServiceDomain.Leave(); }
Seit einigen Tagen existiert ein eigenes Informations-Portal für IT-Architekten (www.architectsconnection.de). Dort stehen sehr viele architekturrelevanten Ressourcen – Fachartikel, Kommentare, Web- und PodCasts, Vorträge, Event-Termine u.v.m zur Verfügung und soll bei den täglichen Aufgaben helfen und unterstützen.
Der Gedanke des Portals ist "Service von Architekten für Architekten". Schauen wir mal wie sich dieses Microsoft Portal entwickelt.
Die ersten Erfahrungen mit dem .NET Framework 2.0 waren sehr erfreulich. Als eines der ersten Features habe ich mir die "Anwendungseinstellungen" vorgenommen und war total begeistert. Endlich wird einem diese lästige Aufgabe komplett abgenommen auch das Binden von Einstellunge auf Eigenschaften eines Controls finde ich super! Nur noch ein Load() und Save() in den Code einbauen und fertig. So dachte ich zumindest aber der Frust kam relativ schnell:
Das Speichern von benutzerabhängigen Einstellungen wird unter c:\Dokumente und Einstellungen\benutzername\.... vorgenommen. So weit kein Problem nur das die Versionsnummer mit im Pfad stehen muss finde ich richtig übel. So bald sich die Versionnummer ändert ist es mit den alten Einstellungen essig ... es gibt zwar eine Upgrade() Methode aber bei der Verwendung von SettingKey funktioniert das nicht mehr :(
Also habe ich versucht den Pfad anzupassen und habe gegoogelt .. siehe da: Es geht nicht .... super gemacht, toll durchdacht aber dann trotzdem leider auf den letzten Metern versaut. Immerhin hat man die Möglichkeit einen eigenenen Provider zu schreiben, um die Einstellungen abzuspeichern. Das wiederum ist klasse gelöst und mehr als sinnvoll!
Nun hier ist eine Provider, der die Einstellungen im XML-Format unter dem Anwendungsverzeichnis speichert:
using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.Configuration; using System.Windows.Forms; using System.Xml; using System.Collections.Specialized; using Microsoft.Win32;
namespace GaliNeo.Framework.GaliNeoSettings { class GaliNeoSettingsProvider : SettingsProvider { XmlDocument doc = null; XmlNode root = null; XmlNode userSettings = null; XmlNode appSettings = null;
public GaliNeoSettingsProvider() { doc = new XmlDocument(); LoadSettings(); }
public override string ApplicationName { get { return Application.ProductName; } set { } }
public override void Initialize(string name, NameValueCollection col) { base.Initialize(this.ApplicationName, col); }
public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection propvals) {
foreach (SettingsPropertyValue propval in propvals) {
SettingsProperty prop = propval.Property;
setValue(prop, propval, context);
}
this.WriteSettings(); }
public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection props) {
// Create new collection of values SettingsPropertyValueCollection values = new SettingsPropertyValueCollection(); string sectionName = this.GetSectionName(context); string settingKey = (string)context["SettingsKey"];
// Iterate through the settings to be retrieved foreach (SettingsProperty setting in props) { SettingsPropertyValue value = new SettingsPropertyValue(setting); value.IsDirty = false; value.SerializedValue = getValue(setting, context );
values.Add(value); } return values;
}
private XmlNode SerializeToXmlElement(SettingsProperty setting, SettingsPropertyValue value) {
XmlElement element = doc.CreateElement("value"); string text1 = value.SerializedValue as string; if ((text1 == null) && (setting.SerializeAs == SettingsSerializeAs.Binary)) { byte[] buffer1 = value.SerializedValue as byte[]; if (buffer1 != null) { text1 = Convert.ToBase64String(buffer1); } } if (text1 == null) { text1 = string.Empty; } if (setting.SerializeAs == SettingsSerializeAs.String) { //text1 = this.Escaper.Escape(text1); }
element.InnerXml = text1; XmlNode node1 = null; foreach (XmlNode node2 in element.ChildNodes) { if (node2.NodeType == XmlNodeType.XmlDeclaration) { node1 = node2; break; } } if (node1 != null) { element.RemoveChild(node1); } return element; }
private string GetSectionName(SettingsContext context) { string groupName = (string)context["GroupName"]; string settingKey = (string)context["SettingsKey"]; string section = groupName; if (!string.IsNullOrEmpty(settingKey)) { object[] arrName = new object[] { section, settingKey }; section = string.Format("{0}.{1}", arrName); } return XmlConvert.EncodeLocalName(section); }
#region DAN
private string getXPathQueryProperty(SettingsProperty setting, SettingsContext context) { string xPathQuery = getXPathQuerySection(setting, context);
if (setting.Name != "") { xPathQuery += "/" + setting.Name; } //if (propName != "")
return xPathQuery; }
private string getXPathQuerySection(SettingsProperty setting, SettingsContext context) { string xPathQueryGroup = doc.DocumentElement.LocalName ;
if (this.IsUserScoped(setting)) { xPathQueryGroup += "/userSettings"; } else { xPathQueryGroup += "/appSettings"; } xPathQueryGroup += "/" + GetSectionName(context);
return xPathQueryGroup;
}
private void CreatePropNode(SettingsProperty setting, SettingsPropertyValue value, SettingsContext context) { string xPathQuery = getXPathQuerySection(setting, context);
XmlNode groupNode = doc.SelectSingleNode(xPathQuery);
if (groupNode == null) { groupNode = doc.CreateElement(GetSectionName(context));
if (this.IsUserScoped(setting)) { userSettings.AppendChild(groupNode); } else { appSettings.AppendChild(groupNode); }
} //if (node == null)
XmlNode nodeProp = doc.CreateElement(setting.Name);
nodeProp.AppendChild (this.SerializeToXmlElement(setting,value) );
groupNode.AppendChild(nodeProp);
}
private void setValue(SettingsProperty setting, SettingsPropertyValue value, SettingsContext context) //string propName, string groupName, object value, object defaultvalue) {
string xPathQuery = getXPathQueryProperty(setting,context);
XmlNode node = doc.SelectSingleNode(xPathQuery); if (node != null) { XmlNode valueNode = SerializeToXmlElement(setting, value); node.RemoveAll(); node.AppendChild(valueNode); } else {
CreatePropNode(setting, value, context);
} //if (node != null)
}
private object getValue(SettingsProperty setting, SettingsContext context) { string xPathQuery = getXPathQueryProperty(setting, context);
XmlNode node = doc.SelectSingleNode(xPathQuery + "/value");
if (node != null) { return node.InnerXml; } else if (setting.DefaultValue != null) { return setting.DefaultValue; } else { return null; }
}
// Helper method: walks the "attribute bag" for a given property // to determine if it is user-scoped or not. // Note that this provider does not enforce other rules, such as // - unknown attributes // - improper attribute combinations (e.g. both user and app - this implementation // would say true for user-scoped regardless of existence of app-scoped) private bool IsUserScoped(SettingsProperty prop) { foreach (DictionaryEntry d in prop.Attributes) { Attribute a = (Attribute)d.Value; if (a.GetType() == typeof(UserScopedSettingAttribute)) return true; } return false; }
#endregion
private void LoadSettings() { string configFile = getPath() + "user.config";
if (System.IO.File.Exists(configFile) ) { doc.Load(configFile); root = doc.DocumentElement; userSettings = doc.DocumentElement.SelectSingleNode("./userSettings"); appSettings = doc.DocumentElement.SelectSingleNode("./appSettings"); ;
} else {
try { root = doc.CreateElement("configuration");
userSettings = doc.CreateElement("userSettings"); root.AppendChild(userSettings); appSettings = doc.CreateElement("appSettings"); root.AppendChild(appSettings);
doc.AppendChild(root); } catch {
} }
}
private string getPath() { return Application.StartupPath + @"\App_Data\" ; }
private void WriteSettings() { if (!( System.IO.Directory.Exists(getPath()))) { System.IO.Directory.CreateDirectory(getPath()); } string configFile = getPath() + "user.config";
doc.Save(configFile);
}
} }
Nun das ist noch nicht 100% best practice Entwicklung (musste schnell gehen) aber es funktioniert ....:)
Bevor ich aber mit .NET 2.0 so richtig loslege hier noch ein kleiner Codebeitrag. Man hat ja immer wieder die Anforderung Daten in CSV zu exportieren (im Zeitalter von XML für mich unverständlich aber gut ). Dafür veröffentliche ich jetzt das fünftausenste Code-Beispiel.
Zunächst habe ich eine allgemeine Basisklasse geschrieben, die auch für weiter Exportformate genutzt werden kann:
using System; using System.Data; using System.Web; using System.Text; using System.IO;
namespace GaliNeo.Framework { /// <summary> /// Zusammenfassung für BaseConverter. /// </summary> public abstract class BaseConverter { public BaseConverter() { }
/// <summary> /// Export DataTable to http stream /// </summary> /// <param name="oDataTable"></param> /// <param name="response"></param> /// <param name="sFileName"></param> public void ExportToResponseStream(DataTable oDataTable, System.Web.HttpResponse response, string sFileName) { response.Clear() ; response.ClearHeaders(); response.ClearContent(); response.Buffer = true; //Very importent because "ü", "ä", usw....
response.ContentEncoding = System.Text.Encoding.Default ; response.ContentType = GetHTTPContentType() ; response.AppendHeader("content-disposition", "attachment; filename=" + HttpUtility.UrlEncode(sFileName, System.Text.Encoding.UTF8)) ;
response.Write( ConvertDataTable(oDataTable).ToString() ) ; //close http response response.End();
}
/// <summary> /// Export datatable to file /// </summary> /// <param name="oDataTable"></param> /// <param name="sFileName"></param> /// <returns></returns> public bool ExportToFile(DataTable oDataTable, string sFileName ) { try { string fullpath = System.IO.Path.GetFullPath( sFileName ) ; if (System.IO.Directory.Exists ( fullpath )) { System.IO.Directory.CreateDirectory( fullpath ) ; }
StreamWriter SW; SW=File.CreateText(sFileName); SW.WriteLine(ConvertDataTable(oDataTable).ToString()); SW.Close(); return true ; } catch { return false ; }
}
protected abstract StringBuilder ConvertDataTable(DataTable oDataTable) ; protected abstract string GetHTTPContentType() ;
} }
Die Klasse ermöglicht es eine Stream entweder auf Festplatte zu schreiben oder aber in den HTTP Responsestream.
Die passende CSV-Klasse ist relativ simple und kein wirkliches Geheimnis:
using System; using System.Data; using System.IO; using System.Text;
namespace GaliNeo.Framework { /// <summary> /// Summary description for CSVConvertor. /// </summary> public class CSVConverter : BaseConverter {
protected override string GetHTTPContentType() { return "text/csv"; }
/// <summary> /// To generate CSV file. /// </summary> /// <param name="oDataTable"></param> /// <param name="directoryPath"></param> /// <param name="fileName"></param> /// <returns></returns> protected override StringBuilder ConvertDataTable(DataTable oDataTable) {
StringBuilder oStringBuilder = new StringBuilder();
// Start, Creating column header
foreach(DataColumn oDataColumn in oDataTable.Columns) { oStringBuilder.Append(oDataColumn.ColumnName + ","); oStringBuilder.Append( System.Environment.NewLine ) ; }
//End, Creating column header //Start, Creating rows
foreach(DataRow oDataRow in oDataTable.Rows) { foreach(DataColumn oDataColumn in oDataTable.Columns) { oStringBuilder.Append(oDataRow[oDataColumn.ColumnName] + ","); }
oStringBuilder.Append( System.Environment.NewLine ) ; }
//End, Creating rows
return oStringBuilder;
} } }
Fertig!
Ab Heute wird die Thematik dieses Blogs ein wenig erweitert. Nun ist es endlich so weit und di Entwicklung mit .NET 2.0 geht bei mir endlich los. In der nächsten Zeit wird der Schwerpunkt mehr auf .NET Winforms und der Google-API liegen.
Aber keine Angst ich werde DotNetNuke nicht wirklich vernachlässigen.
Auch wenn ich es nie gedachte hätte, habe ich heute eine Spammail bekommen die ich doch recht interesannt oder viel mehr sinvoll fand.
Inhalt war eigentlich die Seite http://www.rekruter.de/ eine Seite mit Stellenangebote der Arbeitsargentur. Ob der Staat jetzt auch schon Spammails gegen die Arbeitslosigkeit einsetzt
Heute hat das Coreteam von DotNetNuke ein weiters Modul frei gegeben. Diesmal handelt es sich um ein Modul das eine Shopfunktionalität abbildet. Bei der Installation sollte man darauf achten das man nicht das Module "Categories" von efficionconsulting installiert hat, denn sonst kommt es zu Konflikten bei der Namensgebung. Diese Hürde einmal genommen ist die weiter Installation kein Problem.
Die Funktionalität ist ziemlich Low-Level und an einige Stellen gibt es noch Fehlermeldungen (z.B. bei den Einstellungen). Es gibt aber ein paar ganz gute Ansätze und ich denke das im Laufe der Zeit dieses Modul noch an Funktionsumfang zunimmt. In den nächsten Tagen werde ich wohl auch noch mal in den Source reinschauen ... so einfach aus neugier.
Für mich selber ist dieses Modul eher uninteressant, da mein Shop so langsam die Version 1.0 ereicht hat; auch wenn er laut Zeitplanung schon längst fertig sein sollte .. na ja es kommt halt immer anders als man denkt. Mittlerweile ist die Featureliste schon sehr lang - erspare mir diese aber jetzt. Eines der wichtigsten Merkmale ist aber wohl, dass alle öffentlichen Bereiche über Templates pro Portal dynamisch anpassbar sind. Ebenso ist der Bestellprozess über eine XML Workflowbeschreibung komplett frei definierbar. Anpassbarkeit und Konfigurierbakeit ist bei der Implementierung sehr wichtig gewesen. Das erste Projekt wird vermutlich nächste Woche live gehen aber dann nur für eine bestimme Gruppe von Personen. Wer trotzdem mal mehr darüber wissen möchte, kann sich ja bei mir melden. Was mit dem Shop passiert ist noch nicht ganz klar.
Microsoft stellt im Downloadbereich das IIS Diagnostic Toolkit zur Verfügung. Das ist eine Sammlung von Werkzeugen, die bei der Fehlersuche rund um den IIS (Internet Information Sevices) helfen sollen. Das Toolkit enthält folgende sieben Werkzeuge: Authentication and Access Control Diagnostics 1.0, SSL Diagnostics 1.1, SMTP Diagnostics 1.0, Log Parser 2.2, Trace Diagnostics 1.0, WFetch 1.4 und Debug Diagnostics 1.0.
Hier geht es zum Download
Eines der doch besten Argumente für die Linux- bzw. PHP-Welt im Webumfeld waren bis vor einiger Zeit immer noch die doch sehr teuren Hostingpakete von Windowsbetriebssystemen. Mittlerweile fallen die Preise ständig und sind auf einem Niveau, wie es auch im Linuxumfeld anzutreffen ist.
Das ist besonders für Freunde und Fans von DotNetNuke interessant! Es gibt zwar auch einige Anbieter die ein DotNetNuke Hosting für z.B. 10€ anbiete aber wer gerne Kontrolle über seine System hat sollte sich überlegen einen eigenen Server zu mieten.
Nicht nur das man dort der eigene Administrator ist .. man ist bei vielen Punkten nicht auf den Support seinen Providers angewiesen.
Ganz davon abgesehen, dass man auch weiter Anwendungen auf seinem Server unterbringen kann.
Ich habe nun schon seit über einem Jahr einen Server bei Strato stehen und bin mit dem Service sehr zufrieden. Wer also ein paar Euro mehr ausgibt bekommt dafür auch deutlich mehr geboten. Ich persönlich möchte das nicht mehr missen. Immerhin läuft auch mein Block darüber und ein paar weitere Anwendungen.
Weil ich das Angebot sehr gut finde habe ich oben mal einen Banner eingebaut - wer also einen Buchen will .. einfach klicken :)
Am 15 Januar hat Locopon einen neuen alternativen DotNetNuke Provider für den WYSIWYG Editor FCKEditor zum download bereitgestellt. Zu finden under diesem Link....
Dieser Provider ist ein VB.NET OpenSource Projekt (und damit kostenlos) und stellt eine echte Alternative zur FreeTextBox dar - wenn nicht sogar eine besser Lösung. Die einzelnen Features werden auf der Website näher erklärt.....
Wer eine deutsche Übersetzung sucht ist auf DeutschnetNuke gut aufgehoben.
Ich wollte gerade eine Modul etwas benutzerfreundlicher gestalten und bei einem Link im ToolTip einen Kommantar / Vorschau anzeigen. Der Text der im ToolTip angezeigt werden soll liegt im HTML Format vor. Das macht die Ansicht schwer, da im ToolTip keine HTML-Zeichen verarbeitet werden.
Habe mir dann einfach ein paar Regular Expressions geschrieben, die mir helfen sollen den Text vom HTML zu befreien.
string sHTMLToolTip = ..... //HTML Message
sHTMLToolTip = Regex.Replace( sHTMLToolTip, "<(br|p)>", System.Environment.NewLine , RegexOptions.IgnoreCase | RegexOptions.Multiline);
sHTMLToolTip = Regex.Replace( sHTMLToolTip, "<(.|\n)+?>", "", RegexOptions.IgnoreCase | RegexOptions.Multiline);
Ich glaube auf die RegEx muss ich nicht näher eingehen 
Nachdem ich mein Weblog die letzten 14 Tage etwas stiefmütterlich behandelt habe möchte ich diesen Zustand nun endlich wieder beenden und damit zumindest einen guten Vorsatz durchsetzen 
Ich habe vor ein paar Tagen eine sehr interessante Seite für die Gestaltung von Website gefunden. Diese Seite ist nicht nur für Webdesigner interessant sondern richtet sich an alle Menschen, die gerne eine Website betreiben möchten. Es werden nämlich nicht nur Themen wie HTML, CSS, Frames keine Frames, Hyperlings überprüfen, usw. behandelt sonder auch z.B. rechtliche Bereiche Copyrights (Umgang mit Urheberrechten) oder Disclaimer bis hin zu solchen Themen wie Ergonomie.
Die Seite ist eine große Linksammlung und zu erreichen unter: http://dciwam.de/checkliste/
Der Titel ist mit Sicherheit etwas provokativ gestellt; aus folgendem Grund:
In den frühen Morgenstunden des 24.12 kam der zweite Newsletter - finde die Newsletter übrigens super - von DotNetNuke.com. Hauptthema des Newsletter war das "DotNetNuke® Benefactor Program", dabei handelt es sich um en Mehrwert-Programm rund um DotNetNuke. Insgesamt gibt es vier Programmstufen von 99$ - 799$ mit unterschiedlichen Inhalten bzw. Möglichkeiten (Details hier).
Ist das der erste Schritt aus DotNetNuke ein komerzielles Produkt zu machen? Ich denke nein und es ist eine gute Möglichkeit das Projekt auf Dauer zu sichern. Ob es das Coreteam allerdings hinbekommt ihre Progamm auch so umzusetzen bleibt abzuwarten.
Hans-Peter Schelian (dnnportal.de) hat dazu auch einen Blogeintrag geschrieben und er als offizieller Team Leiter eines DotNetNuke Unterprojekts hat noch mehr Einblick ....
Warten wir ab .....
Bei mein Besuch der Seite www.dotnetnuke.com hab ich bemerkt, dass die Seite schon unter der Version 3.2.2 läuft. Vielleicht können wir ja auf eine baldige Veröffentlichung dieser Version hoffen und damit auf Behebung von Fehlern 
Mehr Infos über Veränderungen gibt es wie immer unter support.dotnetnuke.com ....
Habe gerade bei The Code Project ein ziemlich cooles ASP.NET Control gefunden. Damit kann man einen Kalender genau wie in Outlook darstellen:
http://www.codeproject.com/useritems/daypilot.asp
Habe das Control selber noch nicht ausprobiert aber die Demo sieht schon mal sehr vielversprechend aus! Das Beste zu Schluß: Es ist ein OpenSource Projekt 
Eine kleine Änderung habe ich in der Templateengine vorgenommen: Das Control skin aus der der Methode LoadSkin() habe ich nicht nur für diese Methode zur Verfügung gestellt sondern daraus eine protected Variable innerhalb der Klasse gemacht. Somit kann nun die abgeleitete Klasse immer darauf zugreifen und der "Umweg" über sender (siehe Part 2) kann geändert werden.
Ich brauchte das gerade für eine Hilfsmethode die ich nicht nur innerhalb der Methode InitializeSkin aufrufen möchte.
Keine Ahnung warum ich das nicht direkt so gemacht habe!
Soeben habe ich ein verdammt cooles Tool gefunden, womit ich Outlook als RSS Reader verwenden kann. Es ist unter http://www.attensa.com erhältlich. Sehr gut ist auch, dass man beim Surfen RSS Abo's direkt über das Kontextmenu des IE oder FireFox mit in die Liste aufnehmen kann.
|