AspDotNetStorefront V9 – Creating a Custom Search Control

In a recent forum post over on forums.aspdotnetstorefront.com, there was a discussion about manipulating the new Search control that shipped with version 9.  Rather than just posting the solution there, I thought it might be a good idea to throw this up on the blog so that others might find it as well.

With the v9 release came quite a number of changes to how developers are going to interact and customize AspDotNetStorefront going forward. For those who have been on the platform for years, these changes are going to take some getting used to.  For those who are “day job” asp.net developers, the changes are going to be a breath of fresh air.

One of the areas in version 9 that has changed is how common controls/blocks of code are rendered to your site.  In previous versions, much of this was done with XMLPackages and hard-coded templates.  The site search is one of those areas of AspDotNetStorefront that was hard coded html (with some javascript) on the template.ascx pseudo “master page”.  Now, in version 9, the search control is implemented as a standard ASP.NET Server Control.  If you are lucky/smart enough to have source code, all of the controls can be found in the AspDotNetStorefrontControls project (and namespace) under Search.cs.

In one of our version 9 client projects, we had a need to change how the HTML was rendered with this Search control.  Before we show you code, this is a quick snapshot of the before/after of our search control:

BEFORE:

aspdnsf_oldsearch

AFTER:

aspdnsf_customsearchcontrol

Building an AspDotNetStorefront V9 Custom Search Control:

1. Copy Search.cs to a new file in your App_Code folder.  In our case, we called this new class /App_Code/DemacSearch.cs.  An example of our new class declaration:

   7: using System;

   8: using System.Collections.Generic;

   9: using System.Linq;

  10: using System.Text;

  11: using System.Web;

  12: using System.Web.UI;

  13: using System.Web.UI.WebControls;

  14: using System.Web.UI.HtmlControls;

  15: using System.ComponentModel;

  16: 

  17: namespace DemacControls

  18: {

  19:     /// <summary>

  20:     /// Custom control used for search functionality

  21:     /// </summary>

  22:     public class DemacSearch : CompositeControl

  23:     {

  24:          
 437: 

 438:     }

 439: }

2. Modify the CreateChildControls method, found around 380.  This is where the control builds up it’s list of child controls to render to the web.  In our case, we needed to add some extra HTML to the rendered output so that we could style it more easily.  Here is what our new CreateChildControls() method looks like:

   1: protected override void CreateChildControls()

   2:         {

   3:             Controls.Clear();

   4:             _pnlContainer.Controls.Clear();

   5: 

   6:             Action<Control> addControl = (ctrl) => { _pnlContainer.Controls.Add(ctrl); };

   7:             _pnlContainer.CssClass = "search";

   8:             addControl(new LiteralControl("<div class=\"searchContainer\">"));

   9:             addControl(new LiteralControl("<fieldset>"));

  10: 

  11:             //DEMAC

  12:             //Lets add some more classes to our elements

  13:             _txtSearch.CssClass = "input";

  14:             _lblSearchCaption.CssClass = "search_text";

  15: 

  16:             addControl(_lblSearchCaption);

  17:             addControl(new LiteralControl("&nbsp;"));

  18:             addControl(_txtSearch);

  19:             addControl(new LiteralControl("&nbsp;"));

  20:             addControl(_btnDoSearch);

  21: 

  22:             if (this.ValidateInputLength && !this.DesignMode)

  23:             {

  24:                 //Controls.Add(new LiteralControl("&nbsp;"));

  25:                 // validator

  26:                 _valMinLength.ControlToValidate = _txtSearch.ID;

  27:                 _valMinLength.ErrorMessage = string.Format(this.SearchTextMinLengthInvalidErrorMessage, this.SearchTextMinLength);

  28:                 _valMinLength.ValidationExpression = "[0-9a-zA-Z ]{" + this.SearchTextMinLength.ToString() + ",}";

  29:                 _valMinLength.EnableClientScript = true;

  30:                 _valMinLength.Display = ValidatorDisplay.None; //.Dynamic;

  31:                 _valMinLength.CssClass = this.CssClass + "_error";

  32:                 _valMinLength.Font.Bold = false;

  33:                 _valMinLength.Font.Italic = false;

  34: 

  35:                 addControl(_valMinLength);

  36:                 addControl(_valSummary);

  37:             }

  38: 

  39:             // assign the default button to trigger

  40:             // once any Enter key was pressed inside the area of this container

  41:             // which is usually after typing on the search text and hitting the enter key

  42:             _pnlContainer.DefaultButton = _btnDoSearch.UniqueID;

  43:             addControl(new LiteralControl("</div>"));

  44:             addControl(new LiteralControl("</fieldset>"));

  45: 

  46:             Controls.Add(_pnlContainer);

  47: 

  48:             base.CreateChildControls();

  49:         }

3. Next, modify your web.config <Controls> section and tell your site about the new namespace that contains your custom search control.  Since you’ve placed this code in the App_Config folder there is no need to reference an assembly.  Here is what our modified web.config <Controls> section looks like:

   1: <controls>

   2:         <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

   3:         <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

   4:         <add tagPrefix="aspdnsf" namespace="AspDotNetStorefrontControls" assembly="AspDotNetStorefrontControls" />

   5:         <add tagPrefix="demac" namespace="DemacControls" />

   6:       </controls>

4.  Now, on your template.master page, you can reference this newly created control like follows:

   1: <demac:DemacSearch ID="ctrlSearch" runat="server"

   2:                         SearchCaption="<%$ Tokens: StringResource, common.cs.82 %>"

   3:                         SearchTextMinLength="<%$ Tokens:AppConfigUSInt, MinSearchStringLength %>"

   4:                         SearchTextMinLengthInvalidErrorMessage="<%$ Tokens: StringResource, search.aspx.2 %>"

   5:                         ValidateInputLength="true"

   6:                         ShowValidationMessageBox="true"

   7:                         ShowValidationSummary="false" SearchButtonCSS="go" />

5.  And just for good measure, here is our CSS that nicely modifies the search box to display an image instead of a button along with prettying up the form a bit.

   1: .search fieldset{ border:none;}

   2: .search .go{ border:none;}

   3: .search{ float:left; width:320px;}

   4: .search .searchContainer{ float:left;}

   5: .search .searchContainer fieldset{ outline:none; float:left;}

   6: .search .searchContainer .go{ width:38px; height:30px; cursor:pointer;}

   7: .search .searchContainer .input{ width:184px; margin:3px 6px; padding:3px 8px; height:16px; font-size:12px;}

   8: .search .searchContainer .search_text{ float:left; font-size:14px; font-weight:bold; text-transform:uppercase;}

   9: .search .searchContainer .search_text{ padding:8px 0 0 0;}

  10: 

  11: .search .searchContainer .go { background:url(images/go.gif) no-repeat; }

  12: .search .searchContainer .input { border:#ffc9a0 1px solid; color:#adadad; }

  13: .search .searchContainer .search_text { color:#ff6e00; }

Hope this helps!

This entry was posted in AspDotNetStorefront and tagged , . Bookmark the permalink.