Wednesday, August 14, 2013

Custom Field type in SharePoint 2010

Custom Field for Uploading Documents and Images:

Scenario:

A Custom List has a column for Image and Document URL which is of type Hyperlink or Picture; it is used to store the URL of the Document or Image.
 In order to add an item to this list, we need to perform two steps.
1.       Upload the Picture or Document to some Library
2.       Copy the URL of the uploaded Item and Paste them in the “Hyperlink or Picture” field.
This seems to be a tedious process and looking for an option to upload Image or Document in the same page of Custom List Add Item/Edit Item form. 

Solution:


To reduce the two step process, we have created a Custom field type. This Custom Field type allows us to upload the Image/ Document directly in the Custom list Dialog box itself, which generates a thumbnail/link to show the Image/Document in the list view respectively. If we click on the thumbnail a popup with the real size picture will open and a Link to download the Document.
We have created an option to configure the default Document or Image library in the List settings, which is used to store all the Documents/Images and a reference to this document will be maintained in the list column.

Column types


1.       Enhanced Hyperlink - Field to upload the Documents to the respective Document Library selected in the List settings.
2.       Enhanced Image – Field to upload the Images to the respective Image Library selected in the List settings.

Implementation:


1.       Create a public custom field type class, which inherits from one of the built-in field type classes, such as SPFieldBoolen, SPFieldChoice, or SPFieldText and name it as ImageEnhancerField.cs.
2.       Create another Class file which needs to inherit from BaseFieldControl and name it as ImageEnhancerFieldControl.cs.
3.       Add SharePoint mapped folders to Control Templates and XML.
4.       Create a User Control under Control Templates folder and name it as ImageEnhancerFieldControl.ascx.
Note: User Control must be deployed directly under Control Templates and not in any sub-folders.      
5.       Create an XML file known as the field type deployment file under XML folder and name it as fldtypes_ImageEnhancer.xml.

Creating the Custom Field Class:  [ImageEnhancerField.cs]


1.       Inherit the Class from SPFieldText and add two public constructors using specific parameter list signatures and forward parameters to base class constructors with matching signatures.

class ImageEnhancerCustomField: SPFieldText
    {
//constructors
public ImageEnhancerCustomField (SPFieldCollection fields, string fieldName)
            : base(fields, fieldName)        { }
         public ImageEnhancerCustomField (SPFieldCollection fields, string typeName, string displayName)
            : base(fields, typeName, displayName)        { }


2.       Override the FieldRenderingControl property and define the get value.

public override BaseFieldControl FieldRenderingControl
        {
            get
            {
                SPContext.Current.List.EnableAttachments = false;
                BaseFieldControl fieldControl = new ImageEnhancerControl();
                fieldControl.FieldName = this.InternalName;
                return fieldControl;
            }
        }


3.       Then Override the GetValidatedString method and return the value which needs to store in the Field.

public override string GetValidatedString(object value)
     {
        return value.ToString().ToUpper();
     }

Creating FieldControl.ascx [ImageEnhancerFieldControl.ascx]


SharePoint Rendering Template can work only when we place the ascx file directly under Control Templates folder not into any sub folders. [Please check comments inside]

<SharePoint:RenderingTemplate Id="ImageEnhancerControlRender" runat="server">
   
    <Template>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
<!-- To show the preview of the image in Edit form -->
    <asp:Image ID="ImgThumb" runat="server" />
<!-- To browse to the file from the physical location -->
        <asp:FileUpload runat="server" id="flUpload" size="40"/>  
<!-- To Delete the Image reference in the Edit form -->
        <asp:Button runat="server" ID="btnDelete" Text="Delete"/>
<!-- To validate the Type of File uplodaed -->
        <asp:RegularExpressionValidator runat="server" ErrorMessage="Please upload png,jpeg or gif files only" ControlToValidate="flUpload" id="ImgRegularExpressionValidator" validationexpression="^.+\.(png|jpeg|jpg|gif)$" SetFocusOnError="True"></asp:RegularExpressionValidator> 
<!-- To Error Message in case of any issues -->
                     
        <asp:Label runat="server" id="lblMessage" />
        <asp:Label runat="server" id="lblMessage2" />
        <asp:Label runat="server" id="lblMessage3" />
         </ContentTemplate>
</asp:UpdatePanel>
    </Template>
</SharePoint:RenderingTemplate>

Creating Custom Field Control Class [ImageEnhancerFieldControl]


1.       Inherit the Class from BaseFieldControl and override the DefaultTemplateName property and define the get property value.

protected override string DefaultTemplateName
        {
            //Name of the SharePoint Rendering Template defined in the ascx file.
            get { return "ImageEnhancerControlRender"; }
        }

2.       Override the Value property and define the get & set values. The Value of this field will be stored in this format “File location full path, Thumbnail URL”.

public override object Value
        {
            get
            {
                EnsureChildControls();
               
                    if (hasfile)
                    //if it’s a new file return the path to the file and the path to the thumbnail
                    return httppath + filename + " ," + thumbnailpath;
                else
                {
                    if (!ImgThumb.Visible)
                    {
                        //if it’s going to be erase return a blank string
                        return "";
                    }
                    else
                    {   //if it’s not been modified return the current string
                        return Field.FieldRenderingControl.ItemFieldValue;
                    }
                }               
            }
            set
            {
                try
                {
                    EnsureChildControls();
                    if (!value.ToString().Equals(",") || !value.ToString().Equals(""))
                    {
// Setting the Image thumbnail url to the Image control added earlier
                        ImgThumb.ImageUrl = value.ToString().Substring(value.ToString().IndexOf(',') + 1);
//Setting the Image control and Delete button control visible in Edit Form if value exists
                        ImgThumb.Visible = true;
                        btnDelete.Visible = true;
                    }
                    else
                    {
                        ImgThumb.Visible = false;
                        btnDelete.Visible = false;
                    }
                }
                catch { }
            }
        }

3.       Now define the control how should it behave in New Form, Display Form and Edit Form of List Item [Check the inline comments for description].

protected override void CreateChildControls()
        {
            try
            {
                if (Field == null) return;
                base.CreateChildControls();
                if (ControlMode == Microsoft.SharePoint.WebControls.SPControlMode.Display) return;
                if (ControlMode == SPControlMode.New || ControlMode == SPControlMode.Edit)
                {
                    Stream fs = null;
// As we set the Default Template name to the name of SharePoint rendering template name defined in ascx file.
// Now get the instance all the controls from the TemplateContanier.
                    flUpload = (FileUpload)TemplateContainer.FindControl("flUpload");
                    lblMessage = (Label)TemplateContainer.FindControl("lblMessage");
                    lblMessage2 = (Label)TemplateContainer.FindControl("lblMessage2");
                    lblMessage3 = (Label)TemplateContainer.FindControl("lblMessage3");
                    ImgThumb = (Image)TemplateContainer.FindControl("ImgThumb");
                    btnDelete = (Button)TemplateContainer.FindControl("btnDelete");
                    txtValue = (TextBox)TemplateContainer.FindControl("txtValue");
                    btnDelete.Click += new EventHandler(btnDelete_Click);
                    try
                    {
                        SPContext.Current.Item[Field.Title].Equals("null");
                    }
                    catch (Exception E)
                    {
                        ImgThumb.Visible = false;
                        btnDelete.Visible = false;
                    }
// Checking whether the File upload control has any file
                    if (flUpload.HasFile)
                    {
//Checking the File Content Length
                        if (flUpload.PostedFile.ContentLength <= 524288)
                        {
                            fs = flUpload.PostedFile.InputStream;
                            filename = flUpload.FileName;
                            hasfile = true;
                            flUpload.EnableViewState = false;
                            flUpload = filenull;
                            flUpload.Dispose();
                            flUpload.Enabled = false;
                            fileSize = 0;
                            //TemplateContainer.fin
                        }
                        else
                        {
                            hasfile = true;
                            fileSize = 1;
                            return;
                        }
                    }
                    flUpload.TabIndex = TabIndex;
                    flUpload.CssClass = CssClass;
                    flUpload.ToolTip = Field.Title + " Image";
// Checking the Default Image library is defined or not. We can define the library in List settings.
                    System.Collections.Specialized.NameValueCollection PictureLibrarys;
                    PictureLibrarys = SharepointInformation.QueryCustType(SPContext.Current.Web.Url.ToString(), SPEncode.UrlDecodeAsUrl(SPContext.Current.List.ToString()), "CustomImageStorage", "ImageEnhancerCustomField",Field.Title);
                    if (PictureLibrarys[0].Equals("False"))
                    {
                        flUpload.Enabled = false;
                        lblMessage.Text = "Image cannot be uploaded as no Picture Library is associated with this list. In order to setup Picture Library, go to ";
                        lblMessage2.Text = "'List Settings - General Settings - Enhanced Image / Document Library' ";
                        lblMessage3.Text = "and select existing Picture Library";
                        //lblMessage3.ForeColor = "Red";
                        //lblMessage.ForeColor = "Red";
                        //lblMessage2.ForeColor = "Red";
                        lblMessage.Font.Bold = true;
                        lblMessage2.Font.Bold = true;
                        lblMessage3.Font.Bold = true;
                        lblMessage2.Font.Italic = true;
                        }
                    else
                    {
                        flUpload.Enabled = true;
                        if (lblMessage != null)
                            lblMessage.Visible = false;
                    }
                    //IF THE UPLOAD FIELD HAS INFORMATION
                    if (hasfile)
                    {
                       
                        bool exist = false;
                        if (PictureLibrarys.HasKeys())
                            for (int i = 0; i < PictureLibrarys.Count; i++)
                            {
                                if (PictureLibrarys.GetKey(i).Equals(Field.InternalName) || PictureLibrarys.GetKey(i).Equals(Field.Title))
                                {
                                    exist = true;
                                    break;
                                }
                            }
                        if (exist)
                        {
// Uploads the File to the SharePoint Image library defined in the List settings if File exist.
                            thumbnailpath = SharepointInformation.UploadImage(SPContext.Current.Web.Url.ToString(), fs, PictureLibrarys[Field.Title], "", filename, SPContext.Current.Web);
                           
                            httppath = SPContext.Current.Web.Lists[PictureLibrarys[Field.Title]].ParentWebUrl.ToString() + "/" + SPContext.Current.Web.Lists[PictureLibrarys[Field.Title]].RootFolder.Url + "/";
                        }
                        else
                        {
                            thumbnailpath = "Go to List Settings - Enhanced Image Settings";
                        }
                    }
                }
                
            }
            catch (Exception spe)
            {
                int i = 0;
            }
        }

Creating Field type Deployment file [fldtypes_ImageEnhancer.xml]


Open fldtypes_ImageEnhancer.xml file and copy the below code [Check the inline comments for description].

<?xml version="1.0" encoding="utf-8"?>
<FieldTypes>
       <FieldType>
//Define the Field Type Name here
              <Field Name="TypeName">ImageEnhancerCustomField</Field>
//Define the Parent Type from the new type is getting Inherited
              <Field Name="ParentType">Text</Field>
//Provide the Display name for the Field
              <Field Name="TypeDisplayName">Enhanced Image</Field>
              <Field Name="TypeShortDescription">Enhanced Image</Field>
              <Field Name="UserCreatable">TRUE</Field>
//Specify where all this column should be available
              <Field Name="ShowInListCreate">TRUE</Field>
              <Field Name="ShowInSurveyCreate">TRUE</Field>
              <Field Name="ShowInDocumentLibrary">TRUE</Field>
              <Field Name="ShowInColumnTemplateCreate">TRUE</Field>
              <Field Name="Sortable">TRUE</Field>
              <Field Name="Filterable">TRUE</Field>
// Specify the NameSpace and class details where the implementation is done
              <Field Name="FieldTypeClass">EnhancedPicture.ImageEnhancerCustomField, EnhancedPicture, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b5ecf5690ed59344</Field>
              <Field Name="SQLType">nvarchar</Field>
//Below part is to define how the field should appear in Display Form
              <RenderPattern Name="DisplayPattern">
                     <Switch>
                           <Expr>
                                  <Column />
                           </Expr>
                           <Case Value="" />
                           <Default>
                                  <HTML>
                                  <![CDATA[<SCRIPT>  function PopupPic(sPicURL) { window.open( "/_layouts/EnhancedPicture/popup.aspx?"+sPicURL, "", "HEIGHT=50,WIDTH=50"); }  var path=']]>
          </HTML>                               <Column/>
                                  <HTML>
                                         <![CDATA['; if (path != "," || path != "" || path != " ") {var xsep=path.lastIndexOf(','); var lastind=path.length;                                        document.write("<a href=\"javascript:PopupPic('" + path.substring(0,xsep) + "')\">                                      <IMG border=0 SRC='"+ path.substring(xsep+1,lastind)+"' ALT='" +                                       path.substring(xsep+1,lastind) + "' > </a>");}</SCRIPT>]]>
                                  </HTML>             
                           </Default>
                     </Switch>
              </RenderPattern>
       </FieldType>
</FieldTypes>

 Once we deploy the XML file, we can see the New Field Type in Create Column of the List.

Configuring Image/Document Library:


To configure the default Image/Document library where the Images and Documents needs to be uploaded, Navigate to List Settings à Enhanced Image / Document Library.


Select the Image and Library from the dropdown and Click Accept button. Once the Accept button is clicked we are updating Fields XML of this current list with the selected libraries.


To Add a link under General Settings in List settings page deploy the below Elements.xml.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction
       Id="ImageEnhacer"
       GroupId="GeneralSettings"
       Location="Microsoft.SharePoint.ListEdit"
       Sequence="20"
       Title="Enhanced Image / Document Library"
       RequireSiteAdministrator="TRUE"
       >
    <UrlAction Url="~site/_layouts/EnhancedPicture/PicturePicker.aspx?&amp;siteId={SiteUrl}&amp;listId={ListId}&amp;itemId={ItemId}"/>
  </CustomAction>
</Elements>

 New Item Form
In New Item form we can browse through the file which needs to be uploaded and click on the Save button.



Once the Item is saved, selected document will be uploaded to the respective library and these New Columns will have a reference to the Document / Image. 

Navigate to the Libraries selected in settings page to verify the uploaded Document / Image.


View Item Form

In the View Item Form, we can see the Thumbnail image for the Image field type and a Link to the document for Hyperlink field type



Once clicking on the thumbnail, we can see the Full Image. Upon clicking on the link, document will be downloaded.

Edit Item Form

In Edit Item Form, we can change the Document/Image reference by clicking the Delete button, which will remove the reference and we can upload a new Item.

Related Posts Plugin for WordPress, Blogger...