Geeks With Blogs
Dipesh Bhanani
 
Mostly all who works extensively on SharePoint (including meJ) don’t like to use out-of-box list forms (DispForm.aspx, EditForm.aspx, NewForm.aspx) as interface. Actually these OOB list forms bind hands of developers for the customization. It gives headache to developers to add just one post back event, for a dropdown field and to populate other fields in NewForm.aspx or EditForm.aspx. On top of that clients always ask such stuff. So here I am going to give you guys a flight for SharePoint Customization world. In this blog, I will explain, how to create CustomListForm WebPart. In my next blogs, I am going to explain easy deployment of List Forms through features and last, guidance on using SharePoint web controls.
1.       First thing, create a class library project through Visual Studio and inherit the class with WebPart class.
    public class CustomListForm : WebPart
 
2.       Declare a property called “ControlMode”. The property is used to identify the mode of the List Form. The property is of type SPControlMode which is an enum type with values (Display, Edit, New and Invalid). When we will add this WebPart to DispForm.aspx, EditForm.aspx and NewForm.aspx, we will set this property to Display, Edit and New respectively.
        SPControlMode _ControlMode = SPControlMode.New;
        [Personalizable(PersonalizationScope.Shared),
         WebBrowsable(true),
         WebDisplayName("Control Mode"),
         WebDescription("Set Control Mode"),
         DefaultValue(""),
         Category("Miscellaneous")]
        public SPControlMode ControlMode
        {
            get { return _ControlMode; }
            set { _ControlMode = value; }
        }
  
3.       Now, we need to override the “CreateChildControls()” method and write code to manually add SharePoint Web Controls related to each list fields as well as ToolBar controls.
        protected override void CreateChildControls()
        {
            base.CreateChildControls();
 
            try
            {
                SiteId = SPContext.Current.Site.ID;
                ListId = SPContext.Current.ListId;
                ListName = SPContext.Current.List.Title;
 
                if (_ControlMode == SPControlMode.Display || _ControlMode == SPControlMode.Edit)
                    ItemId = SPContext.Current.ItemId;
 
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    using (SPSite site = new SPSite(SiteId))
                    {
                        //creating a new SPSite with credentials of System Account
                        using (SPWeb web = site.OpenWeb())
                        {
                              //<Custom Code for creating form controls>
                        }
                    }
                });
            }
            catch (Exception ex)
            {
                ShowError(ex, "CreateChildControls");
            }
        }
 
Here we are assuming that we are developing this WebPart to plug into List Forms. Hence we will get the List Id and List Name from the current context. We can have Item Id only in case of Display and Edit Mode. We are writting our code in “SPSecurity.RunWithElevatedPrivileges(delegate(){}” to elevate privileges to credentials of System Account.
Now, let’s get deep down into the main code and expand “//<Custom Code for creating form controls>”.
Before initiating any SharePoint control, we need to set context of “SPControlexplicitly even if the code is written inside “SPSecurity.RunWithElevatedPrivileges(delegate(){}”. Following line does the job.
    //To create SharePoint controls with new web object and System Account credentials
    SPControl.SetContextWeb(Context, web);
 
Now, let’s add main table as container for all controls.
    //Table to render webpart
    Table spTableMain = new Table();
    spTableMain.CellPadding = 0;
    spTableMain.CellSpacing = 0;
    spTableMain.Width = new Unit(100, UnitType.Percentage);
    this.Controls.Add(spTableMain);
 
Here we are going to add Top Toolbar with Save and Cancel button at top as you see in the below screen shot.
 
 
    // Add Row and Cell for Top ToolBar
    TableRow spRowTopToolBar = new TableRow();
    spTableMain.Rows.Add(spRowTopToolBar);
    TableCell spCellTopToolBar = new TableCell();
    spRowTopToolBar.Cells.Add(spCellTopToolBar);
    spCellTopToolBar.Width = new Unit(100, UnitType.Percentage);
 
 
    ToolBar toolBarTop = (ToolBar)Page.LoadControl("/_controltemplates/ToolBar.ascx");
    toolBarTop.CssClass = "ms-formtoolbar";
    toolBarTop.ID = "toolBarTbltop";
    toolBarTop.RightButtons.SeparatorHtml = "<td class=ms-separator> </td>";
 
    if (_ControlMode != SPControlMode.Display)
    {
        SaveButton btnSave = new SaveButton();
        btnSave.ControlMode = _ControlMode;
        btnSave.ListId = ListId;
 
        if (_ControlMode == SPControlMode.New)
            btnSave.RenderContext = SPContext.GetContext(web);
        else
        {
            btnSave.RenderContext = SPContext.GetContext(this.Context, ItemId, ListId, web);
            btnSave.ItemContext = SPContext.GetContext(this.Context, ItemId, ListId, web);
            btnSave.ItemId = ItemId;
        }
        toolBarTop.RightButtons.Controls.Add(btnSave);
    }
 
    GoBackButton goBackButtonTop = new GoBackButton();
    toolBarTop.RightButtons.Controls.Add(goBackButtonTop);
    goBackButtonTop.ControlMode = SPControlMode.Display;
 
    spCellTopToolBar.Controls.Add(toolBarTop);
 
The toolbar is basically user control which is available in ControlTemplates folder of 12Hive. The control basically serves as container for other controls. Here we have use “SaveButton” and “GoBackButton” which are internal SharePoint web controls for save and cancel functionality. We have added both the controls on right buttons section with “toolBarTop.RightButtons.Controls.Add()” method. One can add more buttons with custom events at left or right side. To add controls on left side use, “toolBarTop.Buttons.Controls.Add()” method.
Now, It's time to add Form Toolbar to the page which contains “New Item”, “Edit Item”, “Delete Item”, “Attach File” etc buttons.
 
 
    // Add Row and Cell for FormToolBar
    TableRow spRowFormToolBar = new TableRow();
    spTableMain.Rows.Add(spRowFormToolBar);
    TableCell spCellFormToolBar = new TableCell();
    spRowFormToolBar.Cells.Add(spCellFormToolBar);
    spCellFormToolBar.Width = new Unit(100, UnitType.Percentage);
 
    FormToolBar formToolBar = new FormToolBar();
    formToolBar.ID = "formToolBar";
    formToolBar.ListId = ListId;
    if (_ControlMode == SPControlMode.New)
        formToolBar.RenderContext = SPContext.GetContext(web);
    else
    {
        formToolBar.RenderContext = SPContext.GetContext(this.Context, ItemId, ListId, web);
        formToolBar.ItemContext = SPContext.GetContext(this.Context, ItemId, ListId, web);
        formToolBar.ItemId = ItemId;
    }
    formToolBar.ControlMode = _ControlMode;
    formToolBar.EnableViewState = true;
 
    spCellFormToolBar.Controls.Add(formToolBar);
 
 
The “ControlMode” property will take care of which button to be displayed on the toolbar. E.g. “Attach files”, “Delete Item” in new/edit forms and “New Item”, “Edit Item”, “Delete Item”, “Manage Permissions” etc in display forms.
Now add main section which contains form field controls.
    //Add a Blank Row with height of 5px to render space between ToolBar table and Control table
    TableRow spRowTopLine = new TableRow();
    spTableMain.Rows.Add(spRowTopLine);
    TableCell spCellTopLine = new TableCell();
    spRowTopLine.Cells.Add(spCellTopLine);
    spCellTopLine.Height = new Unit(5, UnitType.Pixel);
    spCellTopLine.Controls.Add(new LiteralControl("<IMG SRC='/_layouts/images/blank.gif' width=1 height=1 alt=''>"));
 
    //Add Row and Cell for Form Controls Section
    TableRow spRowFormControl = new TableRow();
    spTableMain.Rows.Add(spRowFormControl);
    TableCell spCellFormControl = new TableCell();
    spRowFormControl.Cells.Add(spCellFormControl);
    spCellFormControl.Width = new Unit(100, UnitType.Percentage);
 
    //Create form field controls
    CreateFieldControls(web);
    //Add table created in above function with form field controls to the page
    spCellFormControl.Controls.Add(spTableCntl);
 
    TableRow spRowBottomLine = new TableRow();
    spTableMain.Rows.Add(spRowBottomLine);
    TableCell spCellBottomLine = new TableCell();
    spRowBottomLine.Cells.Add(spCellBottomLine);
    spCellBottomLine.CssClass = "ms-formline";
    spCellBottomLine.Height = new Unit(5, UnitType.Pixel);
    spCellBottomLine.Controls.Add(new LiteralControl("<IMG SRC='/_layouts/images/blank.gif' width=1 height=1 alt=''>"));
 
You can add bottom toolbar also to get same look and feel as OOB forms. There are SharePoint controls available like "CreatedModifiedInfo" which displays created and modified information just like OOB list forms.
At last, you need to write following lines to allow unsafe updates for Save and Delete button. If you miss this, you will get most famous error "Security validation for this page....".
    // Allow unsafe update on web for save button and delete button
    if (this.Page.IsPostBack && this.Page.Request["__EventTarget"] != null
        && (this.Page.Request["__EventTarget"].Contains("IOSaveItem")
        || this.Page.Request["__EventTarget"].Contains("IODeleteItem")))
    {
        SPContext.Current.Web.AllowUnsafeUpdates = true;
    }
 
That’s all. We have finished writing Custom Code for adding field control. But something most important thing is skipped. In above code, I have called function “CreateFieldControls(web)”. Let’s see the implementation of the function as below:
 
    private void CreateFieldControls(SPWeb pWeb)
    {
        SPList listMain = pWeb.Lists[ListId];
        SPFieldCollection fields = listMain.Fields;
 
        //Main Table to render all fields
        spTableCntl = new Table();
        spTableCntl.BorderWidth = new Unit(0);
        spTableCntl.CellPadding = 0;
        spTableCntl.CellSpacing = 0;
        spTableCntl.Width = new Unit(100, UnitType.Percentage);
        spTableCntl.CssClass = "ms-formtable";
 
        SPContext controlContext = SPContext.GetContext(this.Context, ItemId, ListId, pWeb);
 
        foreach (SPField listField in fields)
        {
            string fieldDisplayName = listField.Title;
            string fieldInternalName = listField.InternalName;
 
            //Skip if the field is system field or hidden
            if (listField.Hidden || listField.ShowInVersionHistory == false)
                continue;
 
            //Skip if the control mode is display and field is read-only
            if (_ControlMode != SPControlMode.Display && listField.ReadOnlyField == true)
                continue;
 
            FieldLabel fieldLabel = new FieldLabel();
            fieldLabel.FieldName = listField.InternalName;
            fieldLabel.ListId = ListId;
 
            BaseFieldControl fieldControl = listField.FieldRenderingControl;
            fieldControl.ListId = ListId;
            //Assign unique id using Field Internal Name
            fieldControl.ID = string.Format("Field_{0}", fieldInternalName);
            fieldControl.EnableViewState = true;
 
            //Assign control mode
            fieldLabel.ControlMode = _ControlMode;
            fieldControl.ControlMode = _ControlMode;
            switch (_ControlMode)
            {
                case SPControlMode.New:
                    fieldLabel.RenderContext = SPContext.GetContext(pWeb);
                    fieldControl.RenderContext = SPContext.GetContext(pWeb);
                    break;
                case SPControlMode.Edit:
                case SPControlMode.Display:
                    fieldLabel.RenderContext = controlContext;
                    fieldLabel.ItemContext = controlContext;
                    fieldLabel.ItemId = ItemId;
 
                    fieldControl.RenderContext = controlContext;
                    fieldControl.ItemContext = controlContext;
                    fieldControl.ItemId = ItemId;
                    break;
            }
 
            //Add row to display a field row
            TableRow spCntlRow = new TableRow();
            spTableCntl.Rows.Add(spCntlRow);
 
            //Add the cells for containing field lable and control
            TableCell spCellLabel = new TableCell();
            spCellLabel.Width = new Unit(30, UnitType.Percentage);
            spCellLabel.CssClass = "ms-formlabel";
            spCntlRow.Cells.Add(spCellLabel);
            TableCell spCellControl = new TableCell();
            spCellControl.Width = new Unit(70, UnitType.Percentage);
            spCellControl.CssClass = "ms-formbody";
            spCntlRow.Cells.Add(spCellControl);
 
            //Add the control to the table cells
            spCellLabel.Controls.Add(fieldLabel);
            spCellControl.Controls.Add(fieldControl);
 
            //Add description if there is any in case of New and Edit Mode
            if (_ControlMode != SPControlMode.Display && listField.Description != string.Empty)
            {
                FieldDescription fieldDesc = new FieldDescription();
                fieldDesc.FieldName = fieldInternalName;
                fieldDesc.ListId = ListId;
                spCellControl.Controls.Add(fieldDesc);
            }
 
            //Disable Name(Title) in Edit Mode
            if (_ControlMode == SPControlMode.Edit && fieldDisplayName == "Name")
            {
                TextBox txtTitlefield = (TextBox)fieldControl.Controls[0].FindControl("TextField");
                txtTitlefield.Enabled = false;
            }
        }
        fields = null;
    }
 
First of all, I have declared List object and got list fields in field collection object called “fields”. Then I have added a table for the container of all controls. Now it’s time to navigate through all fields and add them to the page if required.
Here we don’t need to add hidden or system fields. We also don’t want to display read-only fields in new and edit forms. Following lines does this job.
            //Skip if the field is system field or hidden
            if (listField.Hidden || listField.ShowInVersionHistory == false)
                continue;
 
            //Skip if the control mode is display and field is read-only
            if (_ControlMode != SPControlMode.Display && listField.ReadOnlyField == true)
                continue;
 
Let’s move to the next line of code.
            FieldLabel fieldLabel = new FieldLabel();
            fieldLabel.FieldName = listField.InternalName;
            fieldLabel.ListId = ListId;
 
            BaseFieldControl fieldControl = listField.FieldRenderingControl;
            fieldControl.ListId = ListId;
            //Assign unique id using Field Internal Name
            fieldControl.ID = string.Format("Field_{0}", fieldInternalName);
            fieldControl.EnableViewState = true;
 
            //Assign control mode
            fieldLabel.ControlMode = _ControlMode;
            fieldControl.ControlMode = _ControlMode;
 
We have used “FieldLabel” control for displaying field title. The advantage of using Field Label is, SharePoint automatically adds red star besides field label to identify it as mandatory field if there is any.
Here is the most important part to understand. The “BaseFieldControl” which will will render the respective web controls according to type of the field. For example, if it’s single line of text, then Textbox, if it’s look up field then it renders dropdown.
Additionally, the “ControlMode” property tells compiler how control will get rendered on various List Forms. In display mode, it will render label with field value. In edit mode, it will render respective control with item value and in new mode, it will render respective control with empty/default value.
Please note that, it’s not always the case when dropdown field will be rendered for Lookup field or Choice field. You need to understand which controls are rendered for which list fields. I am planning to write a separate blog which I hope to publish it very soon.
Moreover, we also need to assign list field specific properties like List Id, Field Name etc to identify which SharePoint List field is attached with the control.
            switch (_ControlMode)
            {
                case SPControlMode.New:
                    fieldLabel.RenderContext = SPContext.GetContext(pWeb);
                    fieldControl.RenderContext = SPContext.GetContext(pWeb);
                    break;
                case SPControlMode.Edit:
                case SPControlMode.Display:
                    fieldLabel.RenderContext = controlContext;
                    fieldLabel.ItemContext = controlContext;
                    fieldLabel.ItemId = ItemId;
 
                    fieldControl.RenderContext = controlContext;
                    fieldControl.ItemContext = controlContext;
                    fieldControl.ItemId = ItemId;
                    break;
            }
 
Here, I have separated the code for New mode and Edit/Display mode because we will not have Item Id to assign in New Mode. We also need to set CSS class for cell containing Label and Controls so that those controls get rendered with SharePoint theme and layout.
            spCellLabel.CssClass = "ms-formlabel";
            spCellControl.CssClass = "ms-formbody";
 
FieldDescription” control is used to add field description if there is any.
   Now it’s time to add some customization,
 
            //Disable Name(Title) in Edit Mode
            if (_ControlMode == SPControlMode.Edit && fieldDisplayName == "Name")
            {
                TextBox txtTitlefield = (TextBox)fieldControl.Controls[0].FindControl("TextField");
                txtTitlefield.Enabled = false;
            }
 
The above code will disable the title field in edit mode.
You can add more code here to achieve more customization according to your requirement. Some of the examples are as follow:
            //Adding post back event on UserField to auto populate some other dependent field
            //in new mode and disable it in edit mode
            if (_ControlMode != SPControlMode.Display && fieldDisplayName == "Manager")
            {
                if (fieldControl.Controls[0].FindControl("UserField") != null)
                {
                    PeopleEditor pplEditor = (PeopleEditor)fieldControl.Controls[0].FindControl("UserField");
                    if (_ControlMode == SPControlMode.New)
                        pplEditor.AutoPostBack = true;
                    else
                        pplEditor.Enabled = false;
                }
            }
 
            //Add JavaScript Event on Dropdown field. Don't forget to add the JavaScript function on the page.
            if (_ControlMode == SPControlMode.Edit && fieldDisplayName == "Designation")
            {
                DropDownList ddlCategory = (DropDownList)fieldControl.Controls[0];
                ddlCategory.Attributes.Add("onchange", string.Format("javascript:DropdownChangeEvent('{0}');return false;", ddlCategory.ClientID));
            }
  
Finally your custom list form is ready to be deployed. Cheers!!!
In next blog, I am going to explain how to create package to deploy Custom ListForms on SharePoint site through Features.
Following are the screenshots of my Custom ListForm WebPart. Let’s play a game, check out your OOB List forms of SharePoint, compare with these screens and find out differences.
 
DispForm.aspx:
 
 
EditForm.aspx:
NewForm.aspx:
 
Enjoy the SharePoint Soup!!!

 

Posted on Thursday, May 13, 2010 2:50 AM SharePoint , Custom ListForm , WebPart | Back to top


Comments on this post: How to create Custom ListForm WebPart

# re: How to create Custom ListForm WebPart
Requesting Gravatar...
Good job !!
Left by Rinkal on May 13, 2010 6:31 PM

# re: How to create Custom ListForm WebPart
Requesting Gravatar...
Very useful and nice article.!
Left by Keval on May 23, 2010 2:09 AM

# re: How to create Custom ListForm WebPart
Requesting Gravatar...
Good article. Thanks and Good Luck!!
Left by Sathish on Jan 26, 2011 8:48 AM

# re: How to create Custom ListForm WebPart
Requesting Gravatar...
Wow, this was the missing piece of the puzzle for me!
SPControl.SetContextWeb(Context, web);

Since I was running in Elevated Priv, I needed to set the ContextWeb or the thread would fail.

I was getting an exception like this:
at Microsoft.SharePoint.WebControls.BaseFieldControl.OnInit(EventArgs e)
at System.Web.UI.Control.InitRecursive(Control namingContainer)

Thanks for sharing!
Left by Joe on Jun 13, 2012 9:18 AM

# re: How to create Custom ListForm WebPart
Requesting Gravatar...
Very nice... Instead of creating HTML programmetically , can we use the HTML design from SPD and use that in our custom page?
Left by Prashant on Mar 19, 2014 1:41 AM

# re: How to create Custom ListForm WebPart
Requesting Gravatar...
You were always great Dipesh!! :)
love this article
Left by pallavi on Jun 23, 2014 12:58 AM

# re: How to create Custom ListForm WebPart
Requesting Gravatar...
Can someone please tell me how to deploy this??
Left by Monsur Ahmed on Jun 29, 2014 10:34 AM

Your comment:
 (will show your gravatar)


Copyright © DipeshBhanani | Powered by: GeeksWithBlogs.net