Click here to Skip to main content
15,867,686 members
Articles / Web Development / ASP.NET
Article

Utilizing SharePoint Form Controls (like OWSDateField)

Rate me:
Please Sign up or sign in to vote.
4.56/5 (6 votes)
3 Jan 20063 min read 66.4K   216   34   16
This article discusses some ways to take advantage of the SharePoint client side controls (like the OWSDate Control) within the SharePoint web parts.

Introduction

If you have ever developed a WebPart for Windows SharePoint services, then you probably have tried to take advantage of some of the client-side controls, like the OWSDateField. If you have, then you know how much of a pain in the rear it is to use them.

The problem

There are several issues involved with using the OWS controls that come built-in with SharePoint services that are in the Microsoft.SharePoint.WebControls namespace:

  1. If you are going to use a control like the OWSDateField, then you must add an OWSForm control to the WebPart's child control collection. If you do not, then you will not be able to utilize the OWSField controls.
  2. If you wish to get the data from the control at the server (in other words, have the data posted back), you must create an OWSSubmitButton control and add it to the form. If you do not, any other posting mechanism will not post the user's input back to the server.

    This is the problem with OWSSubmitButton: there is no server side click event. Microsoft will tell you to check the "IsPostBack" property on the page, but that is not a viable option if you need more than one button that posts back the data, but does different tasks with it.

  3. None of the OWS form controls in the Microsoft.SharePoint.WebControls namespace have the data change events. Even if the data is not posted back, it will not fire an event.

To be blunt, the server-side functionality of the OWS control set is not very robust, yet the client side scripting works quite well.

The solution

For an application I developed in my current position, I needed the aforementioned functionality. However, I found nothing on the Internet that really helped me. Therefore, I dug deep into the server-side and client-side functionality of the OWS control set, and I found an elegant way of fixing the above limitations.

First, I created a base class called OWSBase that handled all of the data postback and value change event handling for all of the derived controls. Next, I created a set of controls (OWSTextField, OWSRichTextField, OWSDateField, OWSNumberField, etc.) derived from this base class, and each generated similar client-side JavaScripting that the SharePoint controls did. In the end, I created a submit button (a new OWSSubmitButton) that causes the form to postback the data and fire a server-side click event.

Here is the code for the OWSBase class:

C#
public abstract class OWSBase : OWSControl, IPostBackDataHandler
{
    /// <SUMMARY>
    /// Displayed information (possibly not used)
    /// </SUMMARY>
    public string Display
    {
        get { return "" + ViewState["Display"]; }
        set { ViewState["Display"] = value; }
    }

    /// <SUMMARY>
    /// Gets or the display text of the item.
    /// </SUMMARY>
    public virtual string Text
    {
        get { return Value; }
        set { /* Do Nothing */ }
    }

    /// <SUMMARY>
    /// The value of the text control
    /// </SUMMARY>
    public virtual string Value
    {
        get { return "" + ViewState["Value"]; }
        set { ViewState["Value"] = value; }
    }

    /// <SUMMARY>
    /// Indicates whether or not the control is a required field. 
    /// </SUMMARY>
    public bool Required
    {
        get
        {
            if (ViewState["Required"] == null)
                Required = false;
            return (bool)ViewState["Required"];
        }
        set { ViewState["Required"] = value; }
    }

    #region IPostBackDataHandler Members

    /// <SUMMARY>
    /// Gets the posted back data.
    /// </SUMMARY>
    /// <PARAM name="postDataKey">data key for this control</PARAM>
    /// <PARAM name="postCollection">collection information</PARAM>
    /// <RETURNS>true if to fire event</RETURNS>
    public virtual bool LoadPostData(string postDataKey, 
                         NameValueCollection postCollection)
    {
        string present = Value;
        Value = postCollection[postDataKey];
        return (present != Value);
    }

    /// <SUMMARY>
    /// Raises the text changed event
    /// </SUMMARY>
    public virtual void RaisePostDataChangedEvent()
    {
        OnValueChanged(EventArgs.Empty);
    }

    /// <SUMMARY>
    /// Helper to raise the value changed event
    /// </SUMMARY>
    /// <PARAM name="e">value</PARAM>
    private void OnValueChanged(EventArgs e)
    {
        if (ValueChanged != null)
            ValueChanged(this, e);
    }

    /// <SUMMARY>
    /// fires when the value changes after a postback. 
    /// </SUMMARY>
    public event EventHandler ValueChanged;
    
    #endregion

    #region Helper Properties

    /// <SUMMARY>
    /// Formats the string for javascripting.
    /// </SUMMARY>
    protected string JavaScriptValue
    {
        get 
        {
            Microsoft.SharePoint.WebControls.
            return Value
                .Replace(@"\", @"\\")
                .Replace("\"", "\\\"")
                .Replace("'", "\'")
                .Replace("\r", "")
                .Replace("\n", "\\n");
            ; 
        }
    }
    #endregion
}

Here is the code for one of the derived controls, OWSDateField. (Note: This OWSDateField is not the same as the OWSDateField in the Microsoft.SharePoint.WebControls namespace):

C#
public class OWSDateField : OWSBase
{
    #region construction

    /// <SUMMARY>
    /// Default constructor
    /// </SUMMARY>
    public OWSDateField() { }

    #endregion

    #region custom properties

    /// <SUMMARY>
    /// Gets or set the number date in a 
    /// .NET date time format. 
    /// </SUMMARY>
    public DateTime DateTime
    {
      get { 
       return 
          SPUtility.CreateSystemDateTimeFromXmlDataDateTimeFormat(Value); 
      }
      set { 
        Value = SPUtility.CreateISO8601DateTimeFromSystemDateTime(value); 
      }
    }

    /// <SUMMARY>
    /// Gets or set whether or not this control 
    /// presents a date only value.
    /// </SUMMARY>
    public bool DateOnly
    {
        get
        {
            if (ViewState["DateOnly"] == null)
                DateOnly = false;
            return (bool)ViewState["DateOnly"];
        }
        set { ViewState["DateOnly"] = value; }
    }

    /// <SUMMARY>
    /// Gets or set whether or not to hide descriptions.
    /// </SUMMARY>
    public bool HideDescription
    {
        get
        {
            if (ViewState["HideDescription"] == null)
                HideDescription = false;
            return (bool)ViewState["HideDescription"];
        }
        set { ViewState["HideDescription"] = value; }
    }

    #endregion

    #region overridden properties

    /// <SUMMARY>
    /// Gets the test string representation of the date.
    /// </SUMMARY>
    public override string Text
    {
        get 
        { 
            if (DateOnly)
                return DateTime.ToString("dddd, MMMM d, yyyy");
            return DateTime.ToString("dddd, MMMM d, yyyy h:mm tt");
        } 
    }

    #endregion

    #region overridden methods

    /// <SUMMARY>
    /// Renders the OWS Control
    /// </SUMMARY>
    /// <PARAM name="wtr">writes out the text control information
    /// </PARAM>
    protected override void Render(HtmlTextWriter wtr)
    {
        wtr.Write(
            "<script>" +
            "fld=new DateField(frm, '{0}', '{1}', '{2}'); " +
            "fld.fDateOnly = {3}; " +
            "fld.fHideDescription = {4}; " +
            "fld.caltype = 1; " +
            "fld.fRequired = {5}; " +
            "fld.BuildUI(); " +
            "</script>",
            UniqueID,
            Display,
            JavaScriptValue,
            DateOnly.ToString().ToLower(),
            HideDescription.ToString().ToLower(),
            Required.ToString().ToLower()
        );
    }
    #endregion
}

Here is the code for the submit button:

C#
/// <SUMMARY>
/// This type is used to specify in what 
/// format this submit button will render.
/// </SUMMARY>
public enum OWSButtonType
{
    Button,
    HyperLink
}

/// <SUMMARY>
/// This control will cause the postback of 
/// sharepoint stuff. 
/// </SUMMARY>
public class OWSSubmitButton : WebControl, IPostBackEventHandler
{
    #region properties

    /// <SUMMARY>
    /// Gets or sets the type of link
    /// </SUMMARY>
    public OWSButtonType ButtonType
    {
        get
        {
            if (ViewState["ButtonType"] == null)
                ButtonType = OWSButtonType.HyperLink;
            return (OWSButtonType)ViewState["ButtonType"];
        }
        set { ViewState["ButtonType"] = value; }
    }

    /// <SUMMARY>
    /// The display text of the button
    /// </SUMMARY>
    public string Text
    {
        get { return "" + ViewState["Text"]; }
        set { ViewState["Text"] = value; }
    }

    #endregion

    #region overridden methods

    /// <SUMMARY>
    /// Overrides the onload event, and emits the javascript.
    /// </SUMMARY>
    protected override void OnLoad(EventArgs e)
    {
        EmitProcessFormScript();
        base.OnLoad(e);
    }

    /// <SUMMARY>
    /// Renders the control
    /// </SUMMARY>
    /// <PARAM name="writer">the html output write to 
    /// which to render</PARAM>
    protected override void Render(HtmlTextWriter writer)
    {
        switch (ButtonType)
        {
            case OWSButtonType.HyperLink:
                writer.Write(
                    "<A class='\"{0}\"' 
                        href='http://www.thecodeproject.com/"{1}/"'>{2}</A>",
                    CssClass,
                    string.Format(
                        "javascript:ProcessOwsForm('{0}', 'Click');",
                        UniqueID),
                    Microsoft.SharePoint.Utilities.SPEncode.HtmlEncode(Text)
                );
                break;
                
            case OWSButtonType.Button:
                writer.Write(
                    "<input class='\"{0}\"' 
                       onclick='\"{1}\"' type='\"button\"' value='\"{2}\"'>",
                    CssClass,
                    string.Format(
                        "ProcessOwsForm('{0}', 'Click');",
                        UniqueID),
                    Microsoft.SharePoint.Utilities.SPEncode.HtmlEncode(Text)
                );
                break;
        }
    }

    #endregion

    #region IPostBackEventHandler Members

    /// <SUMMARY>
    /// Causes the click event to fire
    /// </SUMMARY>
    /// <PARAM name="eventArgument">this is the 
    /// event argument</PARAM>
    public void RaisePostBackEvent(string eventArgument)
    {
        OnClick(EventArgs.Empty);
    }

    #endregion

    #region events

    /// <SUMMARY>
    /// Fires when the submit button is clicked. 
    /// </SUMMARY>
    public event EventHandler Click;

    #endregion

    #region virtual methods

    /// <SUMMARY>
    /// Helper method for the onclick event
    /// </SUMMARY>
    protected virtual void OnClick(EventArgs e)
    {
        if (Click != null)
            Click(this, e);
    }

    #endregion

    #region helper methods

    /// <SUMMARY>
    /// Emits scripting to force the processing 
    /// of the form script. 
    /// </SUMMARY>
    private void EmitProcessFormScript()
    {
        if (!Page.IsClientScriptBlockRegistered(
                              "OWSProcessFormScript"))
        {
            Page.RegisterStartupScript(
                "OWSProcessFormScript",
                "<script> \r\n" +
                "function ProcessOwsForm(ctl, argument) \r\n" +
                "{ \r\n" +
                "    if (frm.fPreviewMode) \r\n" +
                "    { \r\n" +
                "        var L_cantSave_Text = \"This form cannot be " + 
                                "saved when previewing this page.\"; \r\n" +
                "        window.alert(L_cantSave_Text); \r\n" +
                "        return; \r\n" +
                "    } \r\n" +
                "    if (frm.FValidate(true)) \r\n" + 
                "    { \r\n" +
                "        frm.FPostProcess(); \r\n" +
                "        __doPostBack(ctl, argument); \r\n" +
                "    } \r\n" +
                "} \r\n" +
                "</script>"
            );
            Page.GetPostBackEventReference(this);
        }
    }
    #endregion
}

Included in the download files are the following:

  • OWSChoiceField, which uses an Items property with the ListItem's objects to manage items in the choice, it can either be a dropdown list or a radio button choice field. Use the ChoiceFormat property to specify this.
  • OWSTextField, which can be a single or multi-line text field, use the NumLines property.
  • OWSRichTextField, which can get the HTML encoded text with a nice user interface (uses SharePoint client scripting). Use the NumLines property.
  • OWSNumberField

Assumptions

I assume you are familiar with developing WebParts for WSS or SPS. I will not give help with Manifext.xml or DWP files. These controls are meant to be used within the context of a SharePoint WebPart.

About the ZIP file

All that is included in the ZIP file are the source files. There is no project file. You may add these files to an existing project, or you may create a base assembly that you can reference in your WebPart projects.

TestWebPart.cs contains a small example of how to use the controls.

Special considerations

I have only tested these controls when they have been compiled into a class library that has been installed in the Global Assembly Cache, and thus fully trusted by SharePoint. You may need to make changes to the code or .config files if you do not sign your assembly with a strong name and install it in the GAC (using the - globalinstall option with stsadm.exe).

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralWSS v3 b2 - OWSControl, OWSForm deprecated Pin
Tore Olav Kristiansen23-Oct-06 20:46
Tore Olav Kristiansen23-Oct-06 20:46 
GeneralRe: WSS v3 b2 - OWSControl, OWSForm deprecated Pin
User 24195736-Feb-07 4:21
User 24195736-Feb-07 4:21 
GeneralUse in aspx Pin
Tore Olav Kristiansen23-Oct-06 20:33
Tore Olav Kristiansen23-Oct-06 20:33 
QuestionHow to use? Pin
ShubhraSaxena28-Jun-06 21:51
ShubhraSaxena28-Jun-06 21:51 
GeneralJS Error Pin
Carsten Isak Nielsen26-Jun-06 23:47
Carsten Isak Nielsen26-Jun-06 23:47 
AnswerRe: JS Error Pin
roxvogn7-Dec-06 10:38
roxvogn7-Dec-06 10:38 
I'm having the same problem here.
Error: 'frm.FindField(...)' is null or not an object

This could prove to be really usefull if it works.
QuestionProblem with the Submit Button styles Pin
brian.keenan1-May-06 16:11
brian.keenan1-May-06 16:11 
GeneralQuestion About OWSTextField Pin
Daphoenix20-Mar-06 23:06
Daphoenix20-Mar-06 23:06 
GeneralRe: Question About OWSTextField Pin
railerb21-Mar-06 5:26
railerb21-Mar-06 5:26 
GeneralRe: Question About OWSTextField Pin
Daphoenix22-Mar-06 2:25
Daphoenix22-Mar-06 2:25 
GeneralRe: Question About OWSTextField Pin
railerb22-Mar-06 2:58
railerb22-Mar-06 2:58 
GeneralGreat idea! Pin
KLehel17-Mar-06 9:29
KLehel17-Mar-06 9:29 
GeneralNice, But problem Pin
Daphoenix16-Mar-06 21:25
Daphoenix16-Mar-06 21:25 
GeneralRe: Nice, But problem Pin
railerb17-Mar-06 9:30
railerb17-Mar-06 9:30 
GeneralRe: Nice, But problem Pin
Daphoenix19-Mar-06 21:20
Daphoenix19-Mar-06 21:20 
GeneralNicely Done! Pin
Chris_Green13-Jan-06 0:56
Chris_Green13-Jan-06 0:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.