„Kürzlich bearbeitet“ im Wiki ausblenden

Mit diesem Beitrag wird gezeigt wie man die "Kürzlich bearbeitet"-Einträge, die bei Wiki-Bibliotheken in der Schnellstartleiste erscheinen, ausblenden kann. Diese Einträge sind für die meisten Benutzer uninteressant und werden oft sogar als störend empfunden, weil sie die restlichen Einträge der Schnellstartleiste nach unten verschieben und die Links damit nicht mehr an ihrer gewohnten Stelle sind.

Wenn man durch die Seiten einer Wiki-Bibliothek navigiert, sieht der obere Teil der Schnellstartleiste so aus:

Es gibt grundsätzlich zwei Möglichkeiten diese Einträge auszublenden. Beide erfordern Änderungen der Gestaltungsvorlage (Masterpage).

Die erste Möglichkeit besteht darin, den Platzhalter, in dem die Einträge dargestellt werden, unsichtbar zu machen. Man öffnet dazu die Gestaltungsvorlage in SharePoint Designer (Standard ist v4.master) und sucht darin nach PlaceHolderLeftActions:

<asp:ContentPlaceHolder id="PlaceHolderLeftActions" runat="server">

</asp:ContentPlaceHolder>

Der Platzhalter ist in der Gestaltungsvorlage leer und wird später von den Wikiseiten mit Inhalt gefüllt. Man kann den Platzhalter in der Gestaltungsvorlage unsichtbar machen, indem man ein Visible="false" Attribut einfügt:

<asp:ContentPlaceHolder id="PlaceHolderLeftActions" runat="server" Visible="false">

</asp:ContentPlaceHolder>

Der Nachteil dieser Methode ist, daß der Platzhalter für alle Inhalte ausgeblendet wird. Bei meinen Versuchen konnte ich feststellen, daß er von Blogs und Wikis verwendet wird, aber ich möchte nicht ausschließen, daß es nicht auch noch andere Elemente gibt, die dort etwas anzeigen möchten.

Die zweite Möglichkeit erscheint mir deshalb deutlich besser: man kann die "Kürzlich bearbeitet"-Einträge auch per CSS ausblenden. Wenn man sich den HTML-Quelltext einer Wikiseite anschaut (z.B. mit den Entwicklertools im IE), findet man für die Einträge das:

Das heißt also, daß die Einträge in einem eigenen <div> mit einer spezifischen CSS-Klasse s4-recentchanges erzeugt werden. Das kann man sich zunutze machen, indem man diese CSS-Klasse in der Gestaltungsvorlage überschreibt und die Einträge damit ausblendet. Man fügt dazu ganz am Ende des <head>-Bereichs in der Gestaltungsvorlage das hier ein:

<style type="text/css">

  .s4-recentchanges

  {

    display:none;

  }

</style>

Das Ergebnis sollte so aussehen:

Selbstverständlich kann man das auch in eine eigene CSS-Datei auslagern und auf diese in der Gestaltungsvorlage verweisen.

BCS – Application Pool Konto für die Verbindung nutzen (RevertToSelf)

Beim Anlegen eines externen Inhaltstyps aus einer SQL Server Datenbank mit SharePoint Designer 2010 stehen drei Authentifizierungsoptionen zur Auswahl:

  • Identität des Benutzers. Damit wird die Identität des am Browser angemeldeten Benutzers zur Authentifizierung gegenüber SQL Server benutzt. Wegen des sog. Double Hop Problems funktioniert das aber nur wenn Kerberos verwendet wird.

  • Angenommene Windows-Identität. Erfordert einen korrekt konfigurierten Secure Store Service. Die Verbindung wird dann unter einem dort hinterlegten Konto hergestellt.

  • Angenommene Identität. Wie oben, aber es wird kein Windows-Konto verwendet (z.B. für SQL-Authentifizierung).

Im SharePoint Designer sieht das beim Anlegen einer neuen Verbindung zu einem SQL Server so aus:

Es gibt aber eine versteckte vierte Möglichkeit: RevertToSelf. Damit wird die Verbindung zum SQL Server immer unter dem Konto des verwendeten Application Pools hergestellt.

Ich möchte hier ausdrücklich auf die damit verbundenen Sicherheitsprobleme hinweisen. Wenn diese Möglichkeit zugelassen wird, kann sich jeder Benutzer, der das Recht hat externe Inhaltstypen anzulegen, mit jedem System verbinden und dort Daten auslesen, auf die das Application Pool Konto Zugriff hat. Eine ausführliche Diskussion der verschiedenen Authentifizierungsoptionen und vor allem auch der Risiken von RevertToSelf findet sich z.B. hier im Microsoft Business Connectivity Services Team Blog.

Falls man es trotzdem benutzen möchte, muß es zuerst für SharePoint zugelassen werden. Das geht z.B. mit PowerShell:

Man öffnet die SharePoint-Verwaltungsshell über das Startmenü und gibt folgende Befehle ein:

$apps = Get-SPServiceApplication
$bcs = #Hier holt man sich die richtige Anwendung. Man kann z.B.
#einfach $apps eingeben und bekommt dann die Liste aller Anwendungen.
#Die richtige bekommt man dann einfach über ihren Index: $bcs = $apps[i].
$bcs.RevertToSelfAllowed = $true

Im SharePoint Designer erscheint die neue Möglichkeit trotzdem nicht beim Neuanlegen einer Verbindung. Man muß deshalb die Verbindung anlegen, speichern und dann wieder öffnen:

Jetzt kann man als Authentifizierungsmodus BDC Identity auswählen und zukünftig wird die Verbindung unter dem Konto des Application Pools aufgebaut.

Externe Inhaltstypen – mehrere Filter im SharePoint Designer

Seit SharePoint 2010 lassen sich externe Daten relativ einfach per SharePoint Designer einbinden. Man kann dabei auch sehr einfach Filter definieren, so daß die Benutzer später die externen Daten gezielt nach einzelnen Feldern durchsuchen können. Problematisch wird es erst, wenn mehrere Filter definiert werden sollen.

Da ich gerade ziemlich lange dazu gebraucht habe, Filter für mehrere Felder so zu definieren, daß man später gezielt Datensätze nach bestimmten Kriterien durchsuchen kann, hier die korrekte Filterdefinition (leider habe ich mal wieder nur einen englischen SharePoint Designer für die Screenshots).

Ausgangspunkt ist eine Tabelle im SQL Server mit Gerätedaten. Diese sollen später in SharePoint über ein Nachschlagefeld mit einer normalen SharePoint-Liste verknüpft werden. Dabei soll es möglich sein, daß die Benutzer ein Gerät nach Gerätenummer, Typ, Modell usw. suchen können. Zu Testzwecken habe ich dazu in der Tabelle 100.000 Datensätze mit Zufallsdaten erzeugt.

Zur Konfiguration von Filtern öffnet man den externen Inhaltstyp in SharePoint Designer. Filter werden auf den Read List Operationen definiert, die man einfach per Doppelklick öffnet:

Es öffnet sich ein Dialog, bei dem man einfach auf Weiter klickt, um zur Definition der Filterparameter zu gelangen. Ein Limit-Filter sollte dort bereits vorhanden sein (Best practice). Limit-Filter begrenzen die Anzahl der zurückgegebenen Datensätze und verhindern so, daß "versehentlich" tausende von Datensätzen verarbeitet werden müssen.

Wir wollen jetzt zusätzlich mehrere Wildcard-Filter definieren. Mit einem Wildcard-Filter kann in einem Feld der Datenquelle nach Teilzeichenfolgen gesucht werden. D.h. es werden alle Datensätze gefunden, bei denen der gesuchte Text in einem Feld vorkommt (am Anfang, in der Mitte oder am Ende).

Um einen neuen Filter zu erstellen, klickt man unterhalb der Filterliste auf den Button Add Filter Parameter. Es wird ein neuer Filter angelegt, der über die Eigenschaften am rechten Rand konfiguriert werden kann:

Im oberen DropDown wird das Feld ausgewählt, auf das sich dieser Filter beziehen soll. Im unteren Feld kann ein Standardwert für den Filter angegeben werden. Bei einer SQL-Datenquelle und einem Wildcard-Filter gibt man hier ein Prozentzeichen ein. Durch Klick auf den Link über dem Default Value öffnet sich ein Dialog, mit dem weitere Einstellungen festgelegt werden:

Ganz oben wird ein Name für den Filter angegeben (der später nicht mehr geändert werden kann). Diesen Namen sehen die Benutzer später, wenn sie nach einem bestimmten Datensatz suchen (s.u.). Als Filtertyp gibt man Wildcard an und wählt nochmal das Feld aus, auf das sich der Filter beziehen soll. Weitere Einstellungen sind nicht notwendig und dürfen auch nicht gemacht werden, damit mehrere Filter später zusammenarbeiten.

Auf diese Weise kann man Filter für beliebige Felder der Datenquelle definieren. Die einzelnen Filter werden alle mit UND verknüpft, so daß sich dieses Gesamtbild ergibt:

Bei meinen Versuchen war das die einzige Konfiguration, bei der wirklich alle Filter korrekt funktionieren. Bei anderen Einstellungen ergaben sich seltsame Nebeneffekte, wie z.B. daß im falschen Feld gesucht wurde oder daß der Suchtext in allen Feldern enthalten sein mußte.

Für den Benutzer stellt sich die Auswahl dann so dar:

Über das DropDown kann ein Filter ausgewählt werden. In der Textbox rechts davon wird der zu suchende Text eingegeben und man bekommt nur noch Datensätze angezeigt, bei denen der Suchtext im entsprechenden Feld vorkommt.

Datumsvergleiche für bedingte Formatierungen in Datenansichten

Leider mußte ich eben feststellen, daß bedingte Formatierungen mit Datumsvergleichen in einer Datenansicht mit dem XsltListViewWebPart bei deutschen Ländereinstellungen nicht funktionieren.

Wenn man zum Beispiel die Zeilen einer Aufgabenliste je nach Status (abgeschlossen oder nicht) und Fälligkeitsdatum unterschiedlich einfärben möchte, dann funktioniert das nur wenn in der entsprechenden Website ein englisches Datumsformat (MM/DD/YYYY) eingestellt ist. Abweichungen davon, z.B. beim deutschen Format DD.MM.YYYY, sorgen dafür, daß die automatisch erzeugten Datumsvergleiche manchmal fehlschlagen. Ja, richtig: manchmal.

Update: das Problem wurde durch Service Pack 1 behoben.

Wenn man sich im SharePoint Designer 2010 eine bedingte Formatierung "zusammenklickt"…

…dann wird dieser XSL-Code erzeugt:

<xsl:if test="ddwrt:DateTimeTick(ddwrt:GenDisplayName(string($thisNode/@DueDate))) &lt; ddwrt:DateTimeTick(ddwrt:GenDisplayName(string(‚Today‘)))" …

Wie man sieht wird dabei mit der Funktion ddwrt:DateTimeTick gearbeitet (sie liefert die Anzahl Tage seit 01.01.1900). Ein paar Versuche haben gezeigt, daß diese Funktion nur für ein englisches Datum das richtige Ergebnis liefert. Wenn sich ein deutsches Datum englisch interpretieren läßt (z.B. der 07.04. als 4. Juli), wird ein falsches Ergebnis geliefert. Wenn sich ein deutsches Datum gar nicht englisch interpretieren läßt (z.B. der 13.04. als 4. Des dreizehnten Monats), wird einfach 0 (Null) geliefert. Das ist die Erklärung dafür, daß es eben manchmal funktioniert.

Ich habe dann Versuche mit den Funktionen ddwrt:FormatDate und ddwrt:FormatDateTime angestellt. Eigentlich wollte ich damit ein Datum im deutschen Format ins englische Format übertragen und dadurch erreichen, daß die Datumsvergleiche immer korrekt funktionieren. Leider wurde es von Microsoft bis heute nicht für notwendig befunden, die ddwrt-Erweiterungen zu dokumentieren. Die einzige Dokumentation dazu ist vom Oktober 2005 und bezieht sich auf SharePoint 2003. Sehr schade, da diese Erweiterungsfunktionen durchaus nützlich sind bzw. sein könnten.

Wie auch immer: es ist mir nicht gelungen, ein deutsches Datum ins englische Format zu übertragen. Nach ein paar weiteren Versuchen habe ich mich für folgende Lösung entschieden:

<xsl:if test="number(concat(substring(string($thisNode/@DueDate),7,4),substring(string($thisNode/@DueDate),4,2),substring-before(string($thisNode/@DueDate),‘.‘))) &lt; translate(substring-before(ddwrt:TodayIso(),’T‘),‘-‚,“) …

Dieser Vergleich macht genau dasselbe wie der oben gezeigte, funktioniert aber für das deutsche Datumsformat (allerdings nur für das).

Erklärung:

Beide Daten (Fälligkeitsdatum und aktuelles Datum) werden ins Format YYYYMMDD gebracht und das dann verglichen. Mit kleinen Änderungen, sollte sich dieses Vorgehen auf jedes beliebige Datumsformat umbauen lassen. Das Fälligkeitsdatum wird mit Stringfunktionen in seine Bestandteile zerlegt und in der richtigen Reihenfolge ohne Trennzeichen zusammengesetzt. Das aktuelle Datum erhält man von der ddwrt:TodayIso-Funktion bereits in der richtigen Reihenfolge. Es wird einfach alles nach dem ‚T‘ abgeschnitten und das Trennzeichen-Minus entfernt.

Schnellstartleiste in Webpartseiten

Wenn man in SharePoint eine neue Webpartseite anlegt, dann fehlt immer die Schnellstartleiste (Quicklaunch). Das gilt für alle acht standardmäßig vorhandenen Vorlagen. In vielen Fällen mag das in Ordnung sein, aber manchmal möchte man eben auch auf einer solchen Seite die Schnellstartleiste haben.

Um die Schnellstartleiste einzublenden, öffnet man die Seite im SharePoint Designer und wechselt in die Code-Ansicht. Damit man die Änderungen durchführen kann, muß der erweiterte Modus über das Ribbon aktiviert werden (das kann nur ein Websitesammlungs-Administrator). Jetzt sucht man die folgenden Zeilen und löscht sie:

<SharePoint:UIVersionedContent ID=“WebPartPageHideQLStylesUIVersion=“4runat=“server„>
<ContentTemplate>
<style type=“text/css„>
body #s4-leftpanel {
display:none;
}
.s4-ca {
margin-left:0px;
}
</style>
</ContentTemplate>
</SharePoint:UIVersionedContent>

Diese Zeilen sorgen dafür, daß es links keinen Rand gibt. Den Rand brauchen wir aber, damit die Schnellstartleiste überhaupt Platz hat.

In den Webpartseiten ist der Platzhalter für die Schnellstartleiste immer ohne Inhalt neu definiert, womit der eigentliche Inhalt aus der Gestaltungsvorlage (Masterpage) nicht übernommen wird. Das machen wir rückgängig, indem wir die leere Überschreibung einfach löschen:

<asp:Content ContentPlaceHolderId=“PlaceHolderLeftNavBarrunat=“server„></asp:Content>

Damit die Schnellstartleiste immer dieselbe (Mindest-)Breite hat, löschen wir auch gleich die leere Überschreibung für einen weiteren Platzhalter:

<asp:Content ContentPlaceHolderId=“PlaceHolderNavSpacerrunat=“server„></asp:Content>

Das war es auch schon. Seite speichern und ab sofort hat sie die gewohnte Schnellstartleiste.

Änderungen am XSLT einer Datenansicht werden nicht übernommen

Ich habe mich gerade ziemlich lange mit einem sehr seltsamen Problem in SharePoint Designer 2010 herumgeschlagen: wenn man bei einem XsltListViewWebPart Änderungen am XSLT vornimmt, werden diese zwar in der Entwurfsansicht in SharePoint Designer korrekt angezeigt, aber nach dem Speichern sind die Änderungen nur sporadisch im Browser sichtbar. Seltsamerweise werden diese Änderungen zwar meistens, aber eben nicht immer unterschlagen. Lösung: man entfernt alle ddwrt:ghost-Attribute.

Vorgehensweise:

Damit man überhaupt etwas an der Standardansicht eines XsltListViewWebPart ändern kann, muß man zunächst das XSLT zugänglich machen. Wenn man die Seite im SharePoint Designer geöffnet und das Webpart markiert hat, geht das durch Klick auf XSLT anpassen im Reiter Entwurf:

Man kann dort auswählen, ob man nur das Template für das ausgewählte Element, also z.B. eine Tabellenzelle, oder das gesamte XSLT verändern möchte.

Jetzt kann man die Ansicht nach Belieben verändern. Man kann vieles über die vom Designer gebotenen Möglichkeiten machen, wie z.B. einzelnen Spalten eine andere Hintergrundfarbe geben, man kann bedingte Formatierungen anwenden und Schriftarten und -größen ändern. Wer möchte kann auch durch direktes Editieren im XSLT-Code die gesamte Ansicht umgestalten.

Allen diesen Änderungen ist aber gemein, daß sie zwar im Entwurfsfenster von SharePoint Designer korrekt angezeigt werden, aber wenn man sie nach dem Speichern im Browser betrachten will, wird man meist enttäuscht. Die Änderungen werden fast immer beim Speichern unterschlagen. Nach langem Suchen und verzweifeltem Haareraufen habe ich die Lösung dieses Problems gefunden: im Code findet sich an vielen Stellen ein ddwrt:ghost="hide"-Attribut. Wenn man es leer macht (ddwrt:ghost="") oder gleich ganz entfernt, funktioniert alles wie gewünscht. Weil dieses Attribut mehr als 60 Mal im Code vorkommt, bietet sich dafür die Suchen&Ersetzen-Funktion an (Strg+H).

Falls jemand weiß, wozu dieses Attribut da ist oder ob es überhaupt einen Sinn hat, möge er mir das bitte mitteilen. Ich konnte bisher jedenfalls keinen finden.

Eine Liste innerhalb der Websitesammlung anzeigen

Eine Frage, die immer wieder aufkommt, ist die, wie man die Daten einer Liste oder einer Bibliothek in einer anderen Website anzeigen kann.

Bei SharePoint 2007 gab es in der Datenquellenbibliothek von SharePoint Designer 2007 den Link "Mit einer anderen Website verbinden". Damit konnte man sich mit jeder Website innerhalb der Websitesammlung verbinden und dann ganz einfach die Daten aller dort vorhandenen Listen und Bibliotheken anzeigen lassen. Diese Möglichkeit besteht jetzt zwar nicht mehr, aber es ist trotzdem nicht schwierig.

Man geht dazu auf eine beliebige Webpart-Seite der Website, in der sich die Liste oder Bibliothek befindet. Man kann dazu auch einfach die default.aspx verwenden. Man versetzt die Seite in den Bearbeitungsmodus…

…und fügt dann das Webpart der Liste oder Bibliothek ein, das man unter "Listen und Bibliotheken" findet.

Natürlich kann man zum Einfügen des Webparts auch den SharePoint Designer verwenden. Wenn man eine Webpart-Seite geöffnet hat, findet man alle Listen und Bibliotheken im Reiter "Einfügen" unter "Datenansicht".

Das Aussehen des Webparts kann man jetzt nach Belieben verändern. Sobald man damit zufrieden ist, öffnet man die Seite im SharePoint Designer (falls noch nicht geschehen) und markiert das Webpart. Im Reiter "Webpart" findet man oben rechts die Funktion "In Websitekatalog":

Wenn man darauf klickt, erscheint ein Dialog, bei dem man einen Namen und optional eine Beschreibung angeben kann. Voreingestellt ist der Name der Liste oder Bibliothek. Unter diesem Namen erscheint das Webpart später im Webpartkatalog. Wenn man den Dialog mit "OK" bestätigt, erscheint folgende Messagebox:

Hier muß unbedingt auf "Ja" geklickt werden, sonst funktioniert das Webpart später nicht wie erwartet!

Das war’s auch schon. Die Ansicht ist jetzt als wiederverwendbares Webpart im Webpartkatalog gespeichert und kann innerhalb der gesamten Websitesammlung verwendet werden. Man findet es in der Kategorie "Custom" oder "Benutzerdefiniert", aber das läßt sich im Webpartkatalog ändern.

Das Webpart, das weiter oben eingefügt wurde, kann jetzt getrost wieder entfernt werden. Es diente nur dazu, die gewünschte Ansicht in den Webpartkatalog speichern zu können und ist nicht mehr länger notwendig.