Realizzare un controllo con anteprima per il campo PublishingRollupImage in MOSS 2007

Il campo PublishingRollupImage, aggiunto con la Publishing Feature di MOSS 2007, permette di specificare l'icona/immagine che è possibile visualizzare nelle ContentByQueryWebPart. Tipicamente viene inserito nell'EditPanel nei Page Layout in modo che i redattori possano, in fase di editing di una pagina, navigare nelle library del sito per scegliere l'immagine da associare alla pagina che stanno creando.

Può capitare che non si voglia dare l'onere ai redattori di trovare l'immagine navigando nelle liste del sito ma si voglia fornire loro un elenco testuale di possibili scelte visualizzando magari un anteprima dell'immagine relativa. Se ad esempio abbiamo creato un Page Layout per il ContentType Notizia potremmo voler permettere ai redattori di scegliere immagini differenti a seconda del tipo di notizia (importanza, rating, genere).

Vediamo ora un esempio di come si possa realizzare una soluzione al problema esposto sopra. Per prima cosa dobbiamo definire l'interfaccia del controllo che verrà visualizzato nel PL e per farlo creeremo un controllo ASCX con il seguente codice:

 <%@ Control Language="C#" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, 
  PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" 
  Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, 
  PublicKeyToken=71e9bce111e9429c" %>
 <SharePoint:RenderingTemplate ID="PageTypeFieldControl" runat="server">
    <Template>
    <asp:Table runat="server" id="tblPageTypeControl">
    <asp:TableRow>
    <asp:TableCell>
        <asp:DropDownList ID="ddlPageTypes" runat="server" >
            <asp:ListItem Value="Normal.jpg" Selected="True">Normale</asp:ListItem>
            <asp:ListItem Value="Important.jpg">Importante</asp:ListItem>
            <asp:ListItem Value="Urgent.jpg">Molto Urgente</asp:ListItem>
        </asp:DropDownList>
    </asp:TableCell>
    <asp:TableCell><asp:Image ID="imgPreview" runat="server" /></asp:TableCell>
    </asp:TableRow>
    </asp:Table>
    </Template>
</SharePoint:RenderingTemplate>

Come vedete si tratta semplicemente di una tabella con all'interno una DropDownList contenente l'elenco delle immagini ed un oggetto Image che sarà utilizzato per l'anteprima. Tale file dovrà essere salvato nella cartella %program files%\Common Files\Microsoft Shared\Web Server Extensions\12\template\controltemplates\

NB: Questo è solo un esempio, sarebbe sicuramente meglio rendere dinamico l'elenco della DropDownList.

Quello che abbiamo fatto è creare un controllo costituito da un RenderingTemplate a cui abbiamo scelto arbitrariamente di assegnare l'identificativo PageTypeFieldControl. A questo punto dobbiamo creare il controllo vero e proprio che verrà renderizzato tramite il suddetto RenderingTemplate.
Innanzitutto creiamo un progetto di tipo Library e facciamo ereditare la classe da BaseFieldControl:

 using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Publishing;
using Microsoft.SharePoint.Publishing.Fields;
using Microsoft.SharePoint.Publishing.WebControls;
using UI = System.Web.UI.WebControls;
using System.ComponentModel;
using Microsoft.SharePoint;

     public class PageTypeFieldControl : BaseFieldControl
    {
        protected UI.DropDownList ddlPageTypes;
        protected UI.Image imgPreview;
        protected UI.Table tblPageTypeControl;

    }

 Poi dobbiamo associare il RenderingTemplate alla classe facendo il seguente override:

         protected override string DefaultTemplateName
        {
            get
            {
                return "PageTypeFieldControl";
            }
        }

Per evitare di specificare all'interno del controllo ascx il path della lista/cartella contenente le immagini prevediamo una proprietà dell'oggetto da utilizzare allo scopo:

         private string _ImageFolder="";

        [Browsable(true)]
        public string ImageFolder
        {
            get { return _ImageFolder; }
            set { _ImageFolder = value; }
        }

A questo punto facciamo un override del metodo CreateChildControls per impostare delle personalizzazioni agli oggetti come ad esempio i valori iniziali, i fogli di stile CSS e gli eventHandler per la DropDownList.

         protected override void CreateChildControls()
        {
            if (Field == null) return;

            base.CreateChildControls();

            if (ControlMode == SPControlMode.Display)
                return;

            //Tabella HTML contenitrice
            tblPageTypeControl = (UI.Table)this.Controls[0].FindControl(
                  "tblPageTypeControl");
            if (tblPageTypeControl == null) throw new NullReferenceException(
                  "tblPageTypeControl is null. Corrupted PageTypeFieldControl.");
            tblPageTypeControl.TabIndex = TabIndex;
            tblPageTypeControl.CssClass = CssClass;

            //IMG HTML di preview
            imgPreview = (UI.Image)this.Controls[0].FindControl("imgPreview");
            if (imgPreview == null) throw new NullReferenceException("imgPreview 
                    is null. Corrupted PageTypeFieldControl.");
            imgPreview.TabIndex = TabIndex;
            imgPreview.CssClass = CssClass;
            imgPreview.ToolTip = "Anteprima per " + Field.Title;

            //DropDown List
            ddlPageTypes = (UI.DropDownList)this.Controls[0].FindControl(
                   "ddlPageTypes");
            if (ddlPageTypes == null) throw new NullReferenceException(
                   "ddlPageTypes is null. Corrupted PageTypeFieldControl.");
            ddlPageTypes.TabIndex = TabIndex;
            ddlPageTypes.CssClass = CssClass;
            ddlPageTypes.ToolTip = "Scelta per " + Field.Title;
            ddlPageTypes.AutoPostBack = true;
            ddlPageTypes.SelectedIndexChanged += new EventHandler(
                   ddlPageTypes_SelectedIndexChanged);
            
            if (ControlMode == SPControlMode.New || imgPreview.ImageUrl=="")
            {
                ddlPageTypes.SelectedIndex = 0;
                imgPreview.ImageUrl = ImageFolder + ddlPageTypes.SelectedValue;
            }
        }

        void ddlPageTypes_SelectedIndexChanged(object sender, EventArgs e)
        {
            imgPreview.ImageUrl = ImageFolder + ddlPageTypes.SelectedValue;
        }

Volendo possiamo anche fare un override del metodo Focus() per scegliere quale controllo costituente deve avere il focus:

         public override void Focus()
        {
            EnsureChildControls();
            if (ControlMode == SPControlMode.Display)
                return;
            ddlPageTypes.Focus();
        }

Per far sì che il valore del field associato al nostro controllo sia visualizzato e salvato tramite il controllo stesso dobbiamo fare il seguente override:

         public override object Value
        {
            get
            {
                EnsureChildControls();
                if (ControlMode == SPControlMode.Display)
                    return null;

                ImageFieldValue ImageValue = new ImageFieldValue();
                try
                {
                    ImageValue.ImageUrl = ImagesFolder + ddlPageTypes.SelectedValue;
                }catch(Exception ex)
                {
                    ImageValue.ImageUrl="";
                }
                return ImageValue;
            }
            set
            {
                EnsureChildControls();
                ImageFieldValue ImageValue = value as ImageFieldValue;
                string url = ImageValue.ImageUrl;
                if(url!=string.Empty)
                    url = url.Substring(url.LastIndexOf("/")+1);
                ddlPageTypes.SelectedValue = url;
                imgPreview.ImageUrl = ImageValue.ImageUrl;
            }
        }

A questo punto il componente è ultimato. Occorre quindi compilarlo, registrarlo in GAC ed inserirlo tra i SafeControls di Sharepoint.

 Per utilizzarlo sarà sufficiente inserire nel PageLayout l'apposto TagPrefix

<%@ Register Tagprefix="MyWebControls" Namespace="MyNamespace"
Assembly="MyAssembly, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=b39c38c41d5734c2" %>

e la relativa dichiarazione:

<MyWebControls:PageTypeFieldControl id="myPageType" FieldName="PublishingRollupImage"
runat="server" ImageFolder="" CssClass="dateLine">
</MyWebControls:PageTypeFieldControl>

HTH