Home | Blog | Screencasts | Projects
# Sunday, August 03, 2008

I had the task of writing a web part that had a lot of UI code and one of the requirements was that a designer could change the look and layout as a toolpart setting. The smartpart stuff is OK, but it doesn't really provide the kind of flexibility that I was after. I came up with a neat solution that I think is pretty powerful.

We've all seen the example webpart code that has lots of layout controls like tables defined in the CreateChildControls method, it's awful to write and its not easy to change. What we really need is a way to define a template that is provided by an external source and then to hookup our code to perform operations on it.

 

Lets have a look at some sample code:

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

namespace Template
{
    
    public class Template : System.Web.UI.WebControls.WebParts.WebPart
    {
        //string with UI code to be added to the page
        protected string templateHTML = string.Empty;

        //Control IDs, the template must use these ID's
        private string searchButtonID = "searchImgBtn";
        private string allTextID = "allTxt";
        //controls that will be found from the template
        protected TextBox allTxt = null;
        protected ImageButton searchBtn = null;

        public Template()
        {            
        }

        protected override void CreateChildControls()
        {
            if (templateHTML != string.Empty)
            {
                try
                {
                    //create a control that has been parsed by asp.net
                    Control template = Page.ParseControl(templateHTML);
                    //add it to the page
                    this.Controls.Add(template);
                    //search for the known controls
                    allTxt = template.FindControl(allTextID) as TextBox;                    
                    searchBtn = template.FindControl(searchButtonID) as ImageButton;
                    //hook up any events
                    if (searchBtn != null)
                    {
                        searchBtn.Click += new ImageClickEventHandler(btnSearch_Click);
                    }

                }
                catch (Exception err)
                {
                    this.Controls.Add(
                        new LiteralControl(string.Format("Error applying template: {0}", err.Message))
                        );
                }
            }
            else
            {
                this.Controls.Add(new LiteralControl("Please enter a template in the toolpart settings"));
            }

            base.CreateChildControls();
        }

        void btnSearch_Click(object sender, ImageClickEventArgs e)
        {
            //if the template included the textbox, show its results
            if (allTxt != null)
            {
                this.Controls.Add(new LiteralControl("Searched On: " + allTxt.Text));
            }
        }

        [System.Web.UI.WebControls.WebParts.WebBrowsable(true),
        System.Web.UI.WebControls.WebParts.WebDisplayName("Layout Template"),
        System.Web.UI.WebControls.WebParts.WebDescription("Template that is used for layout"),
        System.Web.UI.WebControls.WebParts.Personalizable(
        System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared),
        System.ComponentModel.Category("Template Settings"),
        System.ComponentModel.DefaultValue("")
        ]
        public string TemplateHTML
        {
            get
            {return templateHTML;}

            set
            {templateHTML = value;}
        }
        
    }
}

The template that is set with the toolpart should look like this:

 

<table>
    <tr>
        <td>Search On:</td>
        <td><asp:TextBox ID="allTxt" runat="server" />
    </tr>
    <tr>
        <td colspan="2"><asp:ImageButton runat="server" ID="searchImgBtn" ImageUrl="Search.gif"/>
    </tr>
<table>

Notice how the control IDs match the values in the code, that is important, because we use FindControl to bind the code to the UI.

So what we end up with is a flexible way to define our UI code in a way that most of us are used to. I've used this in a number of places now and haven't seen any issues, drop me a line if you start using this approach.

Sunday, August 03, 2008 1:59:28 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint | Work
Tracked by:
"Web Part Templating – A Better Designer Experience" (Httpcode) [Trackback]
"http://httpcode.com/blogs/PermaLink,guid,3316de97-b13c-4b2f-a01c-e35ae60e5a19.a... [Pingback]
Comments are closed.
Statistics
Total Posts: 191
This Year: 0
This Month: 0
This Week: 0
Comments: 41