Wednesday, May 29, 2013

Visual Webpart – Programmatically Update Webpart Properties from the UserControl

As part of a requirement, I had to implement a custom visual webpart which work somewhat similar to the OOB Content Editor webpart, where it will render a given HTML markup. Purpose of this webpart was to create custom web forms on SharePoint publishing pages, using standard input fields.

In the edit mode of the webpart, textarea needs to be displayed to take HTML markup as the input and upon saving corresponding controls should be rendered. In addition, markup entered need to retain regardless of the browser session.

So my approach was to store text entered in textarea in a webpart property.

Edit mode of the webpart:


Once the page is saved, form will be rendered using the entered html markup. Textarea used to enter markup will be hidden:

In the UserControl of the visual webpart, clicking on ‘Update Control’ button will read the textarea text and set in the webpart property called FormControlsMarkup. Here I had to use SPWebPartManager class to save changes to the webpart.

Then in the next page load, I read above webpart property and render HTML markup in the control while hiding the textarea according to the control mode.

UserControl code:

using System;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;

namespace CustomWebparts.FormBuilder
{
 public partial class FormBuilderUserControl : UserControl
 {
  FormBuilder parentWebpart = null;
  protected void Page_Load(object sender, EventArgs e)
  {
   parentWebpart = (FormBuilder)this.Parent;

   // Create input controls from the markup saved in webpart property
   if (parentWebpart != null && !string.IsNullOrEmpty(parentWebpart.FormControlsMarkup))
   {
    pnlFormControls.Controls.Add(new LiteralControl(parentWebpart.FormControlsMarkup));
   }

   // In the edit mode, show markup editor text area
   if (SPContext.Current.FormContext.FormMode == SPControlMode.Edit || SPContext.Current.FormContext.FormMode == SPControlMode.New)
   {
    txtFormControlsMarkup.Text = parentWebpart.FormControlsMarkup;
    txtFormControlsMarkup.Visible = true;
    btnUpdateControl.Visible = true;
   }
   else
   {
    txtFormControlsMarkup.Visible = false;
    btnUpdateControl.Visible = false;
   }
  }

  protected void btnUpdateControl_Click(object sender, EventArgs e)
  {
   // Read markup from the textarea and update webpart property
   if (parentWebpart != null && !string.IsNullOrEmpty(txtFormControlsMarkup.Text))
   {
    parentWebpart.FormControlsMarkup = txtFormControlsMarkup.Text;

    SPWebPartManager currentWebPartManager = (SPWebPartManager)WebPartManager.GetCurrentWebPartManager(this.Page);
    Guid storageKey = currentWebPartManager.GetStorageKey(parentWebpart);
    currentWebPartManager.SaveChanges(storageKey);
   }
  }
 }
}

Webpart Markup:

<asp:Panel ID="pnlFormControls" runat="server" />

<asp:TextBox ID="txtFormControlsMarkup" runat="server" TextMode="MultiLine" Rows="10" Columns="50"></asp:TextBox>
<asp:Button ID="btnUpdateControl" runat="server" Text="Update Control"  onclick="btnUpdateControl_Click" />

Webpart Code:

using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;

namespace CustomWebparts.FormBuilder
{
 [ToolboxItemAttribute(false)]
 public class FormBuilder : WebPart
 {
  // Visual Studio might automatically update this path when you change the Visual Web Part project item.
  private const string _ascxPath = @"~/_CONTROLTEMPLATES/CustomWebparts/FormBuilder/FormBuilderUserControl.ascx";

  public string FormControlsMarkup { get; set; }

  protected override void CreateChildControls()
  {
   this.ChromeType = PartChromeType.None;
   Control control = Page.LoadControl(_ascxPath);
   Controls.Add(control);
  }
 }
}