W poprzednim postcie opisałem jak za pomocą kontrolki SharePoint ograniczyć widoczność listy użytkowników. Teraz pora zająć się ograniczeniem wyświetlania pól na stronie UserInfo.

To co zrobimy wcale nie jest skomplikowane, jednak dojście do tego wymaga trochę poszukiwań. Jak pewnie większość z was zauważyła bawiąc się SharePoint Designer lub przeglądając kod stron MOSS/WSS, wszystkie strony wyświetlające informacje na temat elementu na liście korzystają z szablonów kontrolek, które następnie uzupełniają o własne pola/kod. Nasuwa się pytanie W jaki sposób MOSS/WSS generuje pola, które ma wyświetlić i skąd wie w jaki sposób je wyświetlić?. Odpowiedź znajduje się w klasie ListFieldIterator.

Klasa w sama w sobie nie posiada dużo metod. Więc przyjrzyjmy się im z bliska:

  • CreateChildControls – metoda, iteracyjne przechodzi przez wszystkie SPField, które są wyciągane z kontekstu danego elementu. Czyli jeżeli jesteśmy na stronie UserInfo, to ContextItem zawiera informacje na temat użytkownika, zaś na stronie Tasks, zawiera informacje dot. zadania. Przy każdym przejściu, metoda sprawdza czy dane pole powinno być wyświetlone (np.: powoduje, że pola ukryte nie są wyświetlane) za pomocą funkcji IsFieldExcluded. Jeżeli pole nie jest wykluczone, następuje jego wyświetlenie.
  • IsFieldExcluded – funkcja, za pomocą własności SPField, takich jak (nazwy samo tłumaczące się więc ich nie będę opisywał):

    itp., oraz za pomocą weryfikacji po polach wbudowanych (SPBuiltinFieldId), hash kodach i porównywania ciągów znaków, decyduje czy dane pole powinno zostać wyświetlone czy nie. Jeżeli wartość zwrócona przez funkcję jest równa true to pole nie jest wyświetlane, w przeciwnym wypadku jest.

  • DefaultTemplateName – własność odziedziczona. Definiuje nazwę domyślna szablonu dla iteratora pól.
  • ExcludeFields – własność dodatkowa, która umożliwia podanie ciągu znaków w następującym formacie:

    internal_field_name_01;#internal_field_name_02;#

    ważne, jest to, by była to nazwa internal kolumny, w przeciwnym wypadku MOSS/WSS zwróci false podczas wykonywania porównań nazwy kolumn.

Znając już wszystkie metody oraz własnośći klasy, możemy od razu zauważyć pewną możliwość zablokowania pewnych pól by się ona nie wyświetlały. W TAGu kontrolki wystarczy dodać ExcludeFields i sprawa powinna być załatwiona :) Tak zgadza się, sprawa będzie załatwiona :)

Jednak nie o to chodzi w tym postcie by iść na łatwiznę :) Cofnijmy się do początku:

„Użytkownicy portalu powinni móc przeglądać dane dot. innego użytkownika, jednakże te dane muszą być ograniczone do Imienia, Nazwiska i działu. Nic innego nie może zostać pokazane jak i także listy użytkowników na których znajdują się wszyscy użytkownicy przypisani do portalu powinny być puste dla użytkownika przeglądającego.”

Jednakże administratorzy, powinni móc przeglądać pełne dane. I tu zaczyna się problem z ExcludeFields, nie jesteśmy bowiem wstanie określić pod jakim warunkiem to pole ma się nie wyświetlić. Jedynie co możemy zrobić to całkowicie nie wyświetlić danego pola.

W celu oprogramowania naszego własnego zachowania, musi stworzyć własną klasę dziedziczącą po ListFieldIterator. W tym celu otwieramy VS2005/2008, tworzymy nowy projekt Class Library, dodajemy referencję do bibliotek SharePoint – w tym wypadku wystarczy, że dodamy referencję do Microsoft.SharePoint.dll. Następnie w własnościach projektu, ustawiamy podpisywanie kluczem, zaś plik Class1.cs kasujemy.

Dodajemy nowy plik, nazywamy go MyIterator.cs i dziedziczymy po ListFieldIterator. Tak z przygotowanym szablonem, możemy zacząć oprogramowywać nasze rozwiązanie.

Jedyną rzeczą jaką musimy zrobić, to przeciążyć metodę IsFieldExcluded:

protected override bool IsFieldExcluded(Microsoft.SharePoint.SPField field)
{
    if(string.Compare(field.InternalName, "EMail", true, CultureInfo.InvariantCulture) == 0)
    {
        if (!SPContext.Current.Web.UserIsWebAdmin
            && !SPContext.Current.Web.UserIsSiteAdmin)
        {
            return true;
        }
    }
 
    return base.IsFieldExcluded(field);
}

W przykładzie, jedynie nie wyświetlam pola E-mail, jednakże nic nie stoi wam na przeszkodzie by dodać tam kolejne pola.

Gotowy kod, kompilujemy, wrzucamy do GAC na maszynie MOSS/WSS, zaś naszą DLL dodajemy do SafeControls w MOSS/WSS Web.config.

Pozostaje nam jeszcze jedna rzecz do zrobienia. Mianowicie włączenie naszej kontrolki :) W tym celu otwieramy plik DefaultTemplates.ascx, znajdujemy kontrolkę o ID: UserListForm, która następnie całą przekopiowujemy do nowego pliku, w moim przypadku (testowym) NoEmailUserInfo.ascx. Teraz należy wykonać kilka operacji. Po pierwsze, musimy zarejestrować tagi SharePoint, w tym celu z pliku DefaultTemplates.ascx kopiujemy cały nagłówek do naszego pliku:

<%@ Control Language="C#" AutoEventWireup="false" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePoint" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.WebControls" %>
<%@ Register TagPrefix="SPHttpUtility" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.Utilities" %>
<%@ Register TagPrefix="wssuc" TagName=" ToolBar" src="~/_controltemplates/ToolBar.ascx" %>
<%@ Register TagPrefix="wssuc" TagName=" ToolBarButton" src="~/_controltemplates/ToolBarButton.ascx" %>

I następnie rejestrujemy nasz tag prefix:

<%@ Register TagPrefix="Gutek" Namespace="Gutek.Samples.WebControls"Assembly="Gutek.Samples, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9bdd615dfd84016b" %>

I ostatecznie podmieniamy kontrolkę:

<SharePoint:ListFieldIterator runat="server"/>

Na naszą:

<Gutek:MyIterator runat="server"/>

Teraz robimy iisreset i rozkoszujemy się naszym własnym iteratorem pól.

PS.: W sieci można już znaleźć dość zaawansowane rozwiązania wykorzystujące ListFieldIterator. Jednym z lepszych przykładów jest SPListDisplaySetting, który umożliwia wam definiowanie wyświetlania poszczególnych pól z listy bezpośrednio na stronie. Całe rozwiązanie dodatkowo wykorzystuje własność Properties od obiektu SPWeb w celu przechowania ustawień. Jednakże przy dużej liczbie list z niestandardowym wyświetlaniem pól, rozwiązanie to powoduje obniżenie wydajności pracy nad obiektem SPWeb, oraz czasu rednerowania poszczególnych elementów na listach. Dlatego zalecam rozsądne korzystanie z tej, jakże miłej, zabawki! :)