Freitag, August 21, 2009, 03:47 PM
Diese Themen sind zwar alles andere als neu, aber ich habe mir nochmal die Mühe gemacht, alle Schritte zusammenzutragen und aufzuschreiben, die nötig sind, um ein eigenes SharePoint Theme automatisch auf neu angelegte Sites anzuwenden und dieses Theme obendrein zur Laufzeit editierbar zu halten. (Ansonsten müsste man zum nachträglichen Ändern jede Site einzeln aktualisieren.)Diese Methode ist meines Wissens nach die einzige Alternative zum Erstellen eigener, individuell gestalteter Templates - hat aber den Vorteil, dass das gesamte Portal immer noch 100% dem Standard entspricht und sich später einmal problemlos migrieren lassen sollte.
1. Custom Theme erstellen
Hier steht, wie man ein custom Theme nach regulärem Schema erstellt
Normale Themes haben allerdings einen entscheidenen Nachteil: Wenn ein Theme einmal auf eine Site angewendet wurde, werden weitere Veränderungen am Theme nicht mehr in der Site übernommen! Wer also 1000 Sites mit eigenem Theme hat und dann feststellt, dass die CSS Datei doch noch mal geändert werden muss, hat ein Problem.
Die beste Lösung hierzu, die im Netz gefunden habe, ist folgende:
1.1
Man erstellt einen neuen Ordner im System (z.B. "Customer_Theme") unter:
...\12\TEMPLATE\LAYOUTS\1033\STYLES\Customer_Theme
und kopiert den gesamten Inhalt des Theme-Ordners (z.B. "Customer") von
...\12\TEMPLATE\THEMES\Customer
in den neuen Ordner.
1.2
Man löscht den Inhalt des alten Theme-Ordners, bis auf die beiden Dateien
Customer.INF und
theme.css
1.3
Man editiert die theme.css und ersetzt den gesamten Inhalt durch fogende beiden Zeilen:
@import "/_layouts/1033/styles/Customer_Theme/mossExtension.css";
@import "/_layouts/1033/styles/Customer_Theme/theme.css";
Das führt dazu, dass das Theme lediglich die beiden angegeben CSS Dateien einbindet. Das Theme braucht man danach auch nie mehr zu ändern, denn Änderungen können jetzt in dem neuen Ordner vorgenommen werden und sind sofort sichtbar!
2. Projektstruktur in Visual Studio erstellen
Es empfiehlt sich, folgende Projektstruktur für das weitere Vorgehen anzulegen:
(Ausgehend von einer standard Class-Library)

Die DLL muss einen Strong Name haben.
Die DeployTTA.bat wird nicht unbedingt benötigt.
Alternativ kann auch mein Beispiel-Projekt verwendet werden:
Download ThemeActivator2008.zip
3. ThemeActivatorReceiver.cs implementieren
Dieser Part ist sehr einfach. Der unten stehende Code kann (bis auf den Namespace) 1:1 übernommen werden und muss nicht weiter angepasst werden:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using System.IO;
namespace Company.SharePoint
{
public class ThemeActivatorReceiver : SPFeatureReceiver
{
private const string Property_DefaultTheme = "DefaultTheme";
private const string Property_ThemeToApply = "ThemeToApply";
public override void FeatureInstalled(SPFeatureReceiverProperties properties)
{
}
public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{
}
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPSite site = properties.Feature.Parent as SPSite;
SPWeb web = properties.Feature.Parent as SPWeb;
if (site != null)
{
web = site.RootWeb;
}
if (web != null)
{
if (properties.Feature.Properties[Property_ThemeToApply] != null)
{
string theme = properties.Feature.Properties[Property_ThemeToApply].Value;
if (!string.IsNullOrEmpty(theme))
{
web.ApplyTheme(theme);
}
}
}
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
SPSite site = properties.Feature.Parent as SPSite;
SPWeb web = properties.Feature.Parent as SPWeb;
if (site != null)
{
web = site.RootWeb;
}
if (web != null)
{
if (properties.Feature.Properties[Property_DefaultTheme] != null)
{
string theme = properties.Feature.Properties[Property_DefaultTheme].Value;
if (!string.IsNullOrEmpty(theme))
{
web.ApplyTheme(theme);
}
}
}
}
}
}
Die Information, welches Theme zu setzen ist, kommt später aus dem XML des Features.
4. Theme Activator-Feature implementieren
Um ein Theme automatisch auf eine Site anzuwenden, muss zunächst ein neues Feature erstellt und deployed werden, das in der Lage ist, bei seiner Aktivierung der aktuellen Site das Gewünschte Theme zu verpassen.
(Später wird das zweite Feature benötigt, welches automatisch das erste Feature aktiviert.)
Hierzu die Datei ThemeActivator\feature.xml mit folgendem XML befüllen:
<Feature Id="86D25ADF-DE83-4238-8EFF-802AB22136C2"
Title="Customer Theme Activator"
Description="Applies the Customer Theme to this site."
Version="1.0.0.0"
Scope="Web"
Hidden="false"
DefaultResourceFile="core"
xmlns="http://schemas.microsoft.com/sharepoint/"
ActivateOnDefault="true"
ReceiverAssembly="Company.SharePoint, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a32a55f152c86b83"
ReceiverClass="Company.SharePoint.ThemeActivatorReceiver"
>
<Properties>
<Property Key="DefaultTheme" Value="none" />
<Property Key="ThemeToApply" Value="Customer" />
</Properties>
</Feature>
Die hervorgehobenen Bereiche sind individuell anzupassen:
Feature Id: Hier eine eigene Guid einfügen
Feature Title: Eigener Name für das Feature (wird in der Feature Übersicht angezeigt)
Feature Description: Entsprechende Beschreibung
ReceiverAssembly: Name der DLL
PublicKeyToken: Der StrongName der Assembly (über "sn.exe -Tp" ermitteln)
ReceiverClass: Namespace+Name der Klasse in der ThemeActivatorReceiver.cs
Property ThemeToApply Value: Name des Themes, wie er in der .INF Datei angegeben wurde
Das Feature wird dann den Code aus dem ThemeActivatorReceiver aufrufen, und den Namen des Themes (hier "Customer") übertragen.
5. ThemeTemplateAssociation Feature implementieren
Das zweite Feature benötigt keinen .NET Code, sondern dient lediglich dazu, beim Anlegen einer neuen Site das erste Feature aufzurufen.
Diese Feature ist auch nicht in der Feature Übersicht sichtbar, sondern ist automatisch aktiv.
In [u]ThemeTemplateAssociation\feature.xml[/u] folgenden Code einfügen:
<Feature Id="FC472661-DE52-4fda-950A-970ED9EAE9E5"
Title="Customer Theme Stapling"
Description="Staples the Customer Theme Feature to all sites."
Version="1.0.0.0"
Scope="Farm"
Hidden="true"
DefaultResourceFile="core"
xmlns="http://schemas.microsoft.com/sharepoint/"
ActivateOnDefault="true"
>
<ElementManifests>
<ElementManifest Location="SiteAssociations.xml" />
</ElementManifests>
</Feature>
Die hervorgehobenen Bereiche wie zuvor entsprechend anpassen.
Danach in die ThemeTemplateAssociation\SiteAssociations.xml folgenden Inhalt einfügen:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<!-- <FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="GLOBAL#0" /> -->
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSMSITE#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSPERS#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="OSRV#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="STS#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="STS#1" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="STS#2" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="MPS#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="MPS#1" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="MPS#2" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="MPS#3" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="MPS#4" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="WIKI#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="BLOG#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="BDR#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="EAWF#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="OFFILE#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="OFFILE#1" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="PWA#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="PWS#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPS#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSMSITE#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSTOC#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSTOPIC#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSNEWS#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSNHOME#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSSITES#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSBWEB#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSCOMMU#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSREPORTCENTER#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSPORTAL#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SRCHCEN#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="PROFILES#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="CMSPUBLISHING#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="BLANKINTERNET#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="BLANKINTERNET#1" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="BLANKINTERNET#2" />
</Elements>
Die Angegebene Guid in jeder Zeile muss mit der Guid aus dem XML des ThemeActivator-Feature übereinstimmen.
Jede Zeile steht hier für einen Vorgegebenen Template Typ aus SharePoint, bei dessen Verwendung das Feature mit der Guid aktiviert wird.
Die auskommentierte Zeile mit GLOBAL#0 soll eigentlich alle Template-Typen mit einschließen, aber scheinbar funktioniert das nicht wie erwartet. Darum ist hier jeder Typ einzeln aufgelistet.
6. Das Installations-Batch erstellen
Der Inhalt der Install.bat sollte folgendermaßen aussehen:
@SET TEMPLATEDIR="C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE"
@SET STSADM="C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN\stsadm"
@SET GACUTIL="C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil"
%GACUTIL% -if bin\debug\Company.SharePoint.dll
xcopy /e /y TEMPLATE\* %TEMPLATEDIR%
%STSADM% -o InstallFeature -filename ThemeActivator\feature.xml -force
%STSADM% -o InstallFeature -filename ThemeTemplateAssociation\feature.xml -force
IISRESET
Im Grunde wird hier nur die DLL des Projektes in den GAC kopiert, die beiden Feature-Verzeichnisse in das FEATURES Verzeichnis von SharePoint kopiert und die beiden Features werden über stsadm.exe installiert.
7. Deployment
Anschließend das Projekt kompilieren, und über den Explorer die Install.bat aufrufen. Damit sollte alles erledigt sein.
Die Install.bat muss natürlich auf dem SharePoint Server selbst ausgeführt werden. Wenn man nicht dort entwickelt hat, am besten alles erstmal dorthin kopieren.
Anschließend sollte in SharePoint das neue "Customer Theme Activator" Feature sichtbar sein. Beim Erstellen einer neuen Site sollte jetzt auch bereits das angegebene Theme verwendet werden und das Feature automatisch aktiv sein.
Wenn dies nicht der Fall ist, wurde evtl. ein Template verwendet, das nicht der SiteAssociations.xml definiert wurde. Am besten man probiert es zunächst mit "Blank" und "Teamsite".
Wenn auf dem Server entwickelt wird, kann man sich auch ganz gewöhnlich mit VisualStudio an den w3wp prozess hängen und den Aufruf des ThemeActivatorReceiver debuggen.
So, und jetzt warten wir auf SharePoint 2010 und hoffen, dass dort alles viel einfacher wird, und wir all diese Merkwürdigkeiten nicht mehr benötigen.
Quellen:
http://www.heathersolomon.com/blog/arch ... hemes.aspx
http://grahamsibley.typepad.com/thought ... lly_a.html
http://www.grahamzero.com/blog/2008/05/ ... aplin.html
| Permalink
| Related Link
Mittwoch, Juni 10, 2009, 11:50 AM
Das hat jetzt zwar nichts mit SharePoint oder .NET zu tun, aber manchmal beschäftigt man sich auch mit anderen Dingen, die es wert sind aufgeschrieben zu werden.So. Z.B. das alte Problem, einen Bereich auf einer Webseite zu zentrieren, ohne dafür Tabellen zu verwenden. Das ist durchaus sehr gut möglich, seltsam nur, dass Microsoft auf der bing Startseite das Bild über eine Tabelle zentriert... dabei geht es doch so viel einfacher und sogar besser!
Hier mal eine kurze und elegante Lösung:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Center Example</title>
<style type="text/css">
body
{
margin: 0px;
padding: 0px;
text-align: center;
}
#centered
{
width: 600px;
height: 400px;
position: absolute;
top: 50%;
left: 50%;
margin-top: -200px; /* = -height/2 */
margin-left: -300px; /* = -width/2 */
border: solid 1px red;
}
</style>
</head>
<body>
<div id="centered">
Diese Box ist zentriert!
</div>
</body>
</html>
Wie man sieht, ist nur ein DIV Tag im BODY nötig, um alles zu zentrieren. Die Größe der Box ist hier 600x400 Pixel. Wenn man die ändern möchte, muss man gleichzeitig die negativen margins mit jeweils der Hälfte angeben.
Getestet unter WinXp mit IE7, FF3.x, Safari, Opera und Chrome.
Nachtrag:
Funktioniert auch unter MaxOS X (Safari + Firefox) und Ubuntu (Firefox)
Montag, April 20, 2009, 11:46 AM
Es ist zwar schon ein paar Tage her, aber immer noch eine Meldung wert:Microsoft hat den SharePoint Designer 2007 zum kostenlosen Download zur Verfügung gestellt!
Und zwar bereits am 2.April.2009 (extra einen Tag später).
Wie oft musste ich Kunden vertrösten und ihnen sagen, dass ich für eine bestimmte Änderung den SharePoint Designer bräuchte, für den sie aber leider keine Lizenz hatten... Aber das hat nun ein Ende.
Für den Download muss man sich registrieren, bzw. sich mit seiner Live-ID einloggen. Danach kann man sich die 300 MB große Installationsdatei recht zügig herunterladen.
Zur Download-Seite
Besten Dank an das SharePoint Team! :)
(Obwohl ich auch sagen muss, dass keine Software so häufig abstürzt wie der SPD.)
Donnerstag, Januar 17, 2008, 01:57 PM
Das Problem haben sicherlich schon viele SharePoint Entwickler gehabt: Man will ein simples RSS-Feed WebPart einbinden um z.B. Nachrichten anzuzeigen und bekommt stattdessen eine Fehlermeldung.Nun, meist liegt das daran, dass man für http Zugriff aus dem Firmennetz zwingend über den Proxy-Server gehen muss. Kein Problem eigentlich, denn schließlich muss man nur in der web.config folgende Zeilen hinzufügen und seinen Proxy-Server eintragen und einen IISReset durchführen:
<defaultProxy>
<proxy proxyaddress="http://proxyserver:port" bypassonlocal="True" />
</defaultProxy>
Das funktioniert aber leider nur, wenn der Proxy-Server anonymen Zugriff erlaubt, denn ist SharePoint für NT-Authentifizierung konfiguriert (das ist meist so), werden keine Credentials weitergereicht, so dass der Proxy die Verbindung verweigert. Leider kann man aber nirgendwo angeben, welche speziellen Credentials SharePoint für den Proxy-Server verwenden soll!
Ein Workaround ist auf jeden Fall, auf dem Proxy die IP-Adresse des SharePoint-Servers freizuschalten, so dass anonyme Zugriffe von dort erlaubt werden. Falls das aber nicht möglich ist, weil die zuständige IT-Abteilung im Unternehmen dies nicht zulässt, hat man zunächst keine Möglichkeit mehr, ein RSS-WebPart zum Laufen zu bringen.
Ob eine Umstellung auf Kerberos das Problem beseitigt, konnte ich bisher nicht testen.
Um dennoch RSS-Feeds anzeigen zu können, habe ich schließlich selbst einen kleinen "Proxy" geschrieben, der sich am Proxy-Server anmeldet und den Request zum WebPart durchschleift! Dadurch erspart man sich Konfigurationen und Diskussionen, muss aber eine neue kleine Webseite einrichten - am besten auf dem SharePoint Server selbst.
Eigentlich ist es ganz einfach:
1. Neues VisualStudio Projekt anlegen vom Typ ASP.NET Web Application
2. Default.aspx leeren, bis auf die Header-Zeile mit der Page-Direktive
3. In der Page_Load Methode folgenden Code einfügen:
string feedUrl = Request.QueryString["feedurl"];
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(feedUrl);
request.Proxy = new WebProxy("http://proxyserver:port", true);
request.Proxy.Credentials = new NetworkCredential("UserNameForProxy", "PasswordForProxy");
HttpWebResponse rssResponse = (HttpWebResponse)request.GetResponse();
Stream responseStream = rssResponse.GetResponseStream();
Encoding enc = Encoding.GetEncoding("ISO-8859-1");
StreamReader reader = new StreamReader(responseStream, enc);
string str;
str = reader.ReadToEnd();
Response.Clear();
Response.ClearContent();
Response.Write(str);
rssResponse.Close();
4. Das Ganze kompilieren und auf den SharePoint-Server in ein Verzeichnis im Inetpub publishen.
5. Im IISManager eine Webseite dafür einrichten (ich habe localhost und einen freien Port verwendet) - nicht vergessen auf .NET 2.0 umzustellen.
6. Im RSS-WebPart die URL unserer gerade erstellten Webseite eintragen, und als feedUrl-Parameter den eigentlichen Feed setzen:
z.B.:
http://localhost:6789/Default.aspx? feedUrl=http://www.news.de/rss_news.xmlUnd voilá - das WebPart lädt die Seite.
Theoretisch kann man zwar jede Webseite so laden, allerdings werden hier relative Pfade von Bildern, oder CSS-Dateien nicht umgeschrieben, so dass eine normale Webseite nicht korrekt angezeigt wird. RSS-Feeds enthalten aber meist nur absolute Pfade, so dass es hier kein Problem geben sollte.
Hinweis:
Benutzername und Passwort sollte man lieber aus der web.config lesen, und möglichst einen speziellen Benutzer verwenden, der ansonsten keine Rechte hat.
Die "feedUrl" kann man natürlich komplett per Query-Parameter übergeben, aber aus Sicherheitsgründen habe ich feste URLs definiert, die man über einen frei definierten Namen per GET angibt. Dann muss man auch nicht die URL beim Aufruf encoden.
Donnerstag, November 1, 2007, 04:52 PM
Wenn man InfoPath mit Forms Services benutzt, hat man oft mit Beschränkungen zu kämpfen, die sehr lästig sein können. So ist es z.B. aus HTML-Technischen Gründen nicht von Natur aus möglich, einem mehrzeiligen Eingabefeld eine Zeichenbeschränkung aufzuzwingen. Das Feld ist schlicht ausgegraut:Das kann sehr nervig sein, wenn man die InfoPath Daten in eine Datenbank speichern möchte, und das Zielfeld nur eine begrenzte Länge hat. Es wäre schön, wenn man die Fehleingabe schon im Browser abfangen könnte.
Mit einem kleinen Kniff kann man dies jedoch auch für die mehrzeiligen Eingabefelder erreichen.
Dazu muss die Validierung für das betreffende Feld eingeschaltet werden: "Data Validation"

Für die Validierung wählt man ein eigenes "Custom Pattern", was letztendlich nichts anderes ist als eine Regular Expression:

Als Pattern wählt man dann einfach folgende RegEx:
(.|[\r\n]){0,255}
Wobei hier 255 Beispielhaft die maximale Anzahl der erlaubten Zeichen ist.
Dadurch darf jedes beliebige Zeichen, inklusive eines Zeilenumbruches eingegeben werden, und zwar mindestens 0-Mal, und maximal 255-Mal.
Der "ScreenTip" wird dann über der Box eingeblendet, und die Eingabebox ist wie gewohnt rot umrandet:

Zurück Weiter

Calendar



