5,557,686 members and growing! (14,385 online)
Email Password   helpLost your password?
Web Development » Custom Controls » General     Intermediate License: The Code Project Open License (CPOL)

Postback-less, Designer Supported ASP.NET 2.0 Color Picker Custom Control

By Mehfuz Hossain

The article explains the detailed steps of creating a designer supported postback-less custom control that will help to build your own.
C#, Javascript, XML, Windows, .NET 2.0, .NET, ASP.NET, Visual Studio, VS2005, Dev

Posted: 11 Jul 2006
Updated: 11 Sep 2008
Views: 62,251
Bookmarked: 59 times
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
22 votes for this Article.
Popularity: 5.81 Rating: 4.32 out of 5
3 votes, 13.6%
1
0 votes, 0.0%
2
2 votes, 9.1%
3
1 vote, 4.5%
4
16 votes, 72.7%
5

Introduction

There are plenty of JavaScript color picker controls available out there, but none them are easy to distribute and fully designer supported. Moreover, integrating a JavaScript color picker to an ASP.NET app is a really awful experience. For this reason, I really felt a need for a color picker control in my toolbox that is easy to use but yet powerful. My idea of a color picker was to give the user a bundled control which he/she can easily drag and drop from the toolbox without writing a single line of code. Also, the control should be such that it doesn't postback every time a color is chosen.

This article is not all about a color picker, but I have tried to give an overview of creating and deploying a custom control in ASP.NET 2.0.

Requirements

Nothing is required in using this control, except you must have one of the Visual Studio 2005 versions that are available out there. Also, I have packaged the control as a VSI file. Therefore, if you have a management studio express installed in your PC, then the VSI package may not install properly. The reason is that it overrides some registry settings. So, you might need to go through the following steps:

  1. Under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Packages\
    {36839529-3AF3-47fa-8194-F4A3FA9F0ED7}
    , change the CodeBase value to use the Visual Studio 8.0 location, for e.g. file:///D:\Program Files\Microsoft Visual Studio 8\Common7\IDE\Microsoft.VisualStudio.ToolBoxControlInstaller.dll.
  2. Under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Packages\
    {36839529-3AF3-47fa-8194-F4A3FA9F0ED7}\SatelliteDll
    , change the Path value to point to the Common7\IDE folder, for e.g. D:\Program Files\Microsoft Visual Studio 8\Common7\IDE\.
  3. Open the Visual Studio command prompt, and run devenv /setup.

Or, you can just reference the colorpickerLib.dll from the "Add a toolbox item" option in the Tools menu of Visual Studio, to include the control in your toolbox.

Behind the Control

The first thing when building the control is to construct the color matrix, which is pretty simple. Create three variables r, g, and b. Set the initial value to five, and construct a nested loop that decreases each of the values on each iteration. Convert the value to HEX, and put the value inside an appropriate row-column position. Here, horizontally, it will have 18 boxes, and vertically, 12 boxes. The colors have been divided up into two sets, so that the lighter set fills up the first part and the darker color set fills the other half.

int onrow = 1;
int oncol = 1;
int count = 1;
string s = string.Empty;
string set1 = string.Empty;
string set2 = string.Empty;
for (int r = 5; r >= 0; r--)
{
    for (int g = 5; g >= 0; g--)
    {
        for (int b = 5; b >= 0; b--)
        {
            if (oncol == 1) s += "<tr>\n";
            s += "\t<td onmouseover=\"colorOver(this);\" " + 
                 "onclick=\"colorClick(this);\" style=\"cursor:pointer;" +
                 "background:#" + ReturnHex(r) + ReturnHex(g) + 
                 ReturnHex(b) + ";\" class=cc></td>\n";
            oncol++;
            if (oncol >= 19)
            {
                s += "</tr>\n";
                oncol = 1;

                if (onrow % 2 == 0)
                {
                    set2 += s;
                }
                else
                {
                    set1 += s;
                }
                s = "";
                onrow++;
            }
            count++;
        }
    }
}

Now, the challenging part. I have to render the matrix in a floating div with a possible high z-index, so that other controls do not overlap it. Also, I have to make sure that when the user chooses a color, it fills up the textbox with the appropriate HEX value without posting the page back to the server. To achieve this, I have created a JavaScript file that has a function which takes in HTML and a div ID (where it floats the matrix), which I have embedded in the resource file along with its stylesheet.

For embedding the resource and for getting the reference of the JS file, I had to do the following:

  1. Right click on the file, set the build action to embedded resource.
  2. Add a line ([assembly: WebResource("ColorPickerLib.default.js", "text/javascript", PerformSubstitution = true)]) to the assemblyInfo.cs file.

Now, ASP.NET has a cool function called GetWebResourceUrl that extracts the contents out from an assembly at runtime. By using that inside the scope of the CreateChildControls method, I have added the following lines which do the task of including the necessary JS script to the hosting page:

ClientScriptManager cs = Page.ClientScript;
cs.RegisterClientScriptInclude("popscript", 
   cs.GetWebResourceUrl(this.GetType(), 
   "ColorPickerLib.default.js"));

So, I have created the color matrix, and created the JS script to render it off. Now, I have to wrap in the stuff which includes creating an image button, floating the matrix div, and setting the color value from the matrix to an appropriate text box (without postback). To achieve that, I have separated the custom control into two parts, one that will hold the image button, and will render the include script and the content div within which the matrix HTML will be rendered. My target was to separate the matrix rendering logic from the main process, so that it will be easier to maintain. Although this is not necessary, I could have achieved that by creating a matrix rendering method that would have returned the same HTML. But, in that case, I won't be able to use the ASP.NET 2.0 composite control features. For example, I would manually have to write the persistence logic for the data controls.

So, first, we have to get the contents from the matrix rendering control, which is in ColorPickerPalate.cs. In each Web control, there is method called RenderContents which takes a reference to HtmlWriter as a parameter. If you create an HtmlWriter object and pass it to the RenderContents method, it will then be populated with the control's HTML output. So, I used this trick to write the control's content in a string. And then, I rendered the string inside a floating div.

StringWriter builder = new StringWriter();
Html32TextWriter writer = new Html32TextWriter(builder);
ColorPickerPalate details = new ColorPickerPalate(this);
details.RenderControl(writer);
builder.Close();

string popup = builder.ToString();
popup = popup.Replace("\r", string.Empty);
popup = popup.Replace("\n", string.Empty);
popup = popup.Replace("\t", string.Empty);

popup = HttpUtility.HtmlEncode(popup);

Here, you must have noticed that I encoded the HTML output. This is to avoid JavaScript errors (I get a JavaScript error on calling the showDiv function because of the HTML tags), so before passing the HTML, I encode it and then pass it through the showDiv function.

// Inside showDiv Function (Part of the code)

_Source = docSource;      
document.getElementById(element).innerHTML = divText;
displayFloatingDiv(element, "Color Picker", 300, 200, x, y);

Inside the displayFloatingDiv function, the content is decoded and set to the floating div.

originalDivHTML = document.getElementById(divId).innerHTML;
originalDivHTML = decode(originalDivHTML);
document.getElementById(divId).innerHTML =  
   addHeader + originalDivHTML; //+ originalDivHTML;

Finally, I have to link the showDiv function, and also, I have to make way so that when a user clicks on the matrix, the return value goes to the appropriate text box. And here, I did a simple trick, which is inside the CreateChildControl method. I added a function for finding the client ID of the assigned control. Actually, the function traverses the page control hierarchy to find the control for which the server side ID is given. Once the control is found, it then passes the client ID to the JavaScript function, which stores the client ID in a global variable of the control's scope (if there are multiple controls, the things won't get messed up).

Inside the FindControl, code goes like this:

if (Root.ID == Id)
    return Root;

foreach (Control Ctl in Root.Controls)
{
    Control FoundCtl = FindControlRecursive(Ctl, Id);

    if (FoundCtl != null)

        return FoundCtl;

}
return null;

And inside the CreateChildControl, I must have the following block of code:

if (!base.DesignMode)
{
    try
    {
        TextBox controlToFind = null;

        if (this.Page.Master != null)
        {
            controlToFind = FindControlRecursive(this.Page.Master, 
                            _Control.ID) as TextBox;
        }
        else
        {
            controlToFind = FindControlRecursive(this.Page, 
                            _Control.ID) as TextBox;
        }

        docSource = controlToFind.UniqueID;
        string popup = CreateColorTemlate();

        _Link.Attributes.Add("onclick", "showDiv( 'windowContent','" + 
                             docSource + "', \"" + popup + "\")");
    }
    catch
    {
        throw new Exception("ControlToSet Property can not be left blank");
    }

Also, I have to traverse separately the Page and Page.Master, as in the master page, the control hierarchy is found in Page.Master. In that case, the Page.Controls is null. Therefore, I should have a condition for that.

Deploying the Control

In ASP.NET 2.0, you can distribute your custom controls easily, by creating a VSI file. The process is pretty simple. Just create a folder, put all the contents inside, and create a manifest that holds the information of the contents. Finally, zip the folder, and change the file extension from ZIP to VSI. That's it.

Inside the manifest, in the case of a custom control, I have to write the following information:

<?xml version="1.0" encoding="utf-8" ?>
<VSContent xmlns="http://schemas.microsoft.com/developer/vscontent/2005">

    <Content>
        <FileName>ColorPickerLib.dll</FileName>
        <DisplayName>Color Picker</DisplayName>
        <Description>Postback less easy to use color picker</Description>

        <FileContentType>Toolbox Control</FileContentType>
        <ContentVersion>2.0</ContentVersion>
    </Content>
</VSContent>

Usage

Drag and drop the control from the toolbox to the page. From the list of textboxes, choose the appropriate one in the ControlToSet property. Press F5.

Revision

  • July 11, 2006 - Initial release with full IE support
  • Nov 11, 2006 - Patch (Fix for Mozilla)
  • Aug 20, 2008 - Master page fix (Firefox and IE)[User request]
  • Sept 11, 2008 - Demo updated

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Mehfuz Hossain


Passionate about cutting edge technologies and a .net enthusiast. I have played roles in variety of products starting from University automation to web 2.0 start-page (www.pageflakes.com).

Currently, working at Telerik Inc (www.telerik.com), the premium rad control provider for asp.net and winforms. I am a active contributor and member at www.dotnetslackers.com. In addition, i do a frequent post on my blog about LINQ, C#, Asp.net and about my projects.

I am Microsoft MVP. I love to travel and meet cool people.
Occupation: Software Developer
Company: Telerik Corporation
Location: Bangladesh Bangladesh

Other popular Custom Controls articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 70 (Total in Forum: 70) (Refresh)FirstPrevNext
Subject  Author Date 
Generaltextbox not updating with new colormemberdextrous111:35 9 Sep '08  
GeneralRe: textbox not updating with new colormemberMehfuz Hossain22:32 9 Sep '08  
GeneralRe: textbox not updating with new color [modified]memberdextrous14:36 10 Sep '08  
GeneralRe: textbox not updating with new colormemberdextrous112:53 10 Sep '08  
GeneralRe: textbox not updating with new colormemberMehfuz Hossain20:53 10 Sep '08  
GeneralVS 2008 version?memberdextrous15:11 5 Sep '08  
GeneralRe: VS 2008 version?memberMehfuz Hossain6:38 5 Sep '08  
GeneralRe: VS 2008 version?memberdextrous19:02 5 Sep '08  
GeneralImageUrl property suggestionmemberEmiliano Parizzi9:16 13 May '08  
GeneralReally Your site is great...membersumantmunna6:49 24 Jan '08  
GeneralRe: Really Your site is great...memberMehfuz Hossain8:29 10 Mar '08  
GeneralProblem when using with masterpage and usercontrolmemberRobert Miller8:05 4 Dec '07  
Questionthis doesn't work for mememberalan.pieroway13:18 1 Nov '07  
GeneralPage Scrollmembertcordon7:04 17 Sep '07  
GeneralRe: Page ScrollmemberMehfuz Hossain7:26 18 Sep '07  
GeneralUsing Color Picker in GridViewmemberfeege18:18 31 Jul '07  
GeneralRe: Using Color Picker in GridViewmemberMehfuz Hossain7:38 1 Aug '07  
GeneralHow to change the control's imagememberRobotH18:50 25 May '07  
GeneralRe: How to change the control's imagememberMehfuz Hossain20:40 26 May '07  
GeneralTweaks to the colorpicker (adding greyscale) [modified]memberMr-Markus15:21 22 May '07