Welcome to AspAdvice Sign in | Join | Help

Alessandro Gallo

.NET & Beyond
Extending the AutoCompleteExtender
The December release of Atlas introduces the concept of ExtenderControls. Extenders are server controls that allow to extend a set of ASP.NET server controls by adding client side functionality.

Basically, an ExtenderControl
  • gives a better design timeexperience by allowing to treat extender's properties like properties ofthe controls that it is targeting;
  • renders Atlas markup on pageto add the specified client side functionality. For example, theAutoCompleteExtender included in the December release will add an AutoCompleteBehavior to the behaviors collection of the targetcontrol. The markup is rendered by the method RenderScript(), inheritedfrom the base ExtenderControl class (all the extenders inherit fromthis base class).
As said above, the new Atlas release comes with the AutoCompleteExtender, which can be used for example to add auto-complete behavior to one or a whole set of TextBoxes on our page:

<asp:TextBox ID="myTextBox" runat="server"></asp:TextBox>

<atlas:AutoCompleteExtender ID="ace1" runat="server">
      <atlas:AutoCompleteProperties TargetControlID="myTextBox"
                                    ServicePath="MyWebService.asmx"
                                    ServiceMethod="GetSuggestions"
                                    Enabled="true" />
</atlas:AutoCompleteExtender>

Looking at the AutoCompleteExtender, you'll notice that the control lacks support for the minimumPrefixLength property of the AutoCompleteBehavior class. This property allows to set the minimum length, for the typed text, that activates the auto-completion feature.

We want to add support for this property by "extending" the AutoCompleteExtender. The strategy is
  1. Derive a class from AutoCompleteProperties and expose a MinimumPrefixLength property.
  2. Derive a class from AutoCompleteExtender and override the RenderScript() method that renders the Atlas markup, to include the new property.
  3. Test the control by building an auto-complete TextBox using the custom AutoCompleteExtender.
Step 1. Inherit from AutoCompleteProperties
This class exposes at server side the properties of the AutoCompleteBehavior class found in the Atlas framework. At the moment, the AutoCompleteProperties class doesn't support the minimumPrefixLength property offered by the AutoCompleteBehavior. We want to declare a class called CustomAutoCompleteProperties that inherits from AutoCompleteProperties and adds the support for the MinimumPrefixLength property.


CustomAutoCompleteProperties.cs

namespace AtlasNotesExamples.Controls
{
    public class CustomAutoCompleteProperties : AutoCompleteProperties
    {
        public int MinimumPrefixLength
        {
            get
            {
                object obj = base.ViewState["MinimumPrefixLength"];
                if (obj != null)
                    return (int)obj;
                else
                    return 3; // Default value for minimumPrefixLength.
            }
            set
            {
                base.ViewState["MinimumPrefixLength"] = value;
                base.OnChanged(EventArgs.Empty);
            }
        }
    }
}

Step 2: Inherit from AutoCompleteExtender and override RenderScript()
The RenderScript() method, inherited from the base ExtenderControl class, renders the needed Atlas markup on page.
We have to override this method to render the added property.


CustomAutoCompleteExtender.cs

namespace AtlasNotesExamples.Controls
{
public class CustomAutoCompleteExtender : AutoCompleteExtender
{
    protected override void RenderScript(Microsoft.Web.Script.ScriptTextWriter writer, Control targetControl)
    {
        // Get our CustomAutoCompleteProperties.
        CustomAutoCompleteProperties props
           = (CustomAutoCompleteProperties)base.GetTargetProperties(targetControl);

        if ((props != null) && props.Enabled)
        {
            // Check if the ServicePath is set.
            string sPath = props.ServicePath;
            if (sPath == String.Empty)
            {
                sPath = this.ServicePath;
            }
            if (sPath == String.Empty)
            {
                throw new InvalidOperationException("The ServicePath must be set for AutoCompleteBehavior");
            }
            // Check if the ServiceMethod is set.
            string sMethod = props.ServiceMethod;
            if (sMethod == String.Empty)
            {
                sMethod = this.ServiceMethod;
            }
            if (sMethod == String.Empty)
            {
                throw new InvalidOperationException("The ServiceMethod must be set for AutoCompleteBehavior");
            }
            // Search for the completion list control if an ID was supplied.
            Control cntrl = null;
            string ddpID = this.DropDownPanelID;
            if (ddpID != String.Empty)
            {
                cntrl = this.NamingContainer.FindControl(ddpID);
                if (cntrl == null)
                {
                    throw new InvalidOperationException("The specified DropDownPanelID is not a valid ID");
                }
            }
           
            // Write the Atlas markup on page.
            writer.WriteStartElement("autoComplete");
            writer.WriteAttributeString("serviceURL", base.ResolveClientUrl(sPath));
            writer.WriteAttributeString("serviceMethod", sMethod);
            if (cntrl != null)
            {
                writer.WriteAttributeString("completionList", cntrl.ClientID);
            }
            writer.WriteAttributeString("minimumPrefixLength", Convert.ToString(props.MinimumPrefixLength));
            writer.WriteEndElement();
        }
    }
}
}

Step 3. Build an example using the CustomAutoCompleteExtender
Finally, we could create a simple auto-complete TextBox using the CustomAutoCompleteExtender. Notice the <%@ Register> directive at the top of the Page, to enable declarative usage of our controls.

<%@ Page Language="C#" %>
<%@ Register Namespace="AtlasNotesExamples.Controls" TagPrefix="myatlas" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>CustomAutoCompleteExtender example</title>
    <atlas:ScriptManager ID="scriptManager" runat="server">
        <Services>
            <atlas:ServiceReference Path="MyWebService.asmx" />
        </Services>
    </atlas:ScriptManager>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:TextBox ID="myTextBox" runat="server"></asp:TextBox>
        <myatlas:CustomAutoCompleteExtender ID="cace1" runat="server">
            <myatlas:CustomAutoCompleteProperties
                             TargetControlID="myTextBox"
                             ServicePath="MyWebService.asmx"
                             ServiceMethod="GetSuggestions"
                             MinimumPrefixLength="1"
                             Enabled="true" />
        </myatlas:CustomAutoCompleteExtender>
    </div>
    </form>
</body>
</html>

In the example above, we declared a TextBox and extended it using the CustomAutoCompleteExtender. We have set the MinimumPrefixLength property to initially call our service method when we type one character in the text field. The service method is named GetSuggestions and is part of the MyWebService class declared in MyWebService.asmx

Summary
An extender control allows to add Atlas functionality to a whole set of ASP.NET server controls.
  • The base class for an extender control is ExtenderControl<T>, where T inherits from the TargetControlProperties class.
  • The TargetControlProperties type exposesthe properties that extend the target control, while theExtenderControl class uses these properties to render the needed Atlasmarkup on page.
  • Properties can be added by inheritingfrom an existing TargetControlProperties type, while the way the markupis rendered on page is controlled by overriding the RenderScript() method of the ExtenderControl class.

Sponsor
Posted: Monday, January 02, 2006 6:25 PM by Garbin

Comments

ChrisTorng said:

By the code above, you just add a property named "MinimumPrefixLength". I don't see any code "to start suggestion when text length is more than the specified MinimumPrefixLength". Why can it work?
# January 4, 2006 3:22 AM

Garbin said:

Chris,
it works because the CustomAutoCompleteExtender class overrides the RenderScript() method and adds the statement

writer.WriteAttributeString("minimumPrefixLength", Convert.ToString(props.MinimumPrefixLength));

that adds the minimumPrefixLength attribute to the Atlas markup. The attribute's value is that of the MinimumPrefixLength property defined in the CustomAutoCompleteProperties class.
# January 4, 2006 12:23 PM

ChrisTorng said:

I can't name a "MaximunPrefixLength" property and hope it just work for "stop suggestion when the length reach this property", right? I found "_minimumPrefixLength" property in Atlas.js, so this works because the property "_minimumPrefixLength" is already exist in that script, right? I still can't understand how the "minimumPrefixLength" match to underlined "_minimumPrefixLength", but I think I can just accept this conversion. And I found "_completionSetCount" and "_completionInterval" in script, so I can use the same method to define my "CompletionSetCount" and "CompletionInterval" and it just work, right? If I want other feature, I must modify the Atlas.js to do what I want, right?
# January 4, 2006 8:31 PM

Garbin said:

Chris,

the minimumPrefixLength that you found in the script is an attribute of the
AutoCompleteBehavior element:

<autoCompleteBehavior minimumPrefixLength="1" ... />

At runtime, this script (the Atlas markup) is parsed and object are instantiated at client
side based on the markup.
Thus, when the <autoCompleteBehavior> element is found, an instance of the framework's
Web.UI.AutoCompleteBehavior class is created (you can find the class definition in Atlas.js).
When the minimumPrefixLength attribute is found,
because attributes are mapped to objects' properties, a function set_minimumPrefixLength()
is called (it is a convention, that a setter is a function that begins with the prefix set_),
which sets the _minimumPrefixLength field declared in the AutoCompleteBehavior class.

And yes, you can use the same method to add support for completionInterval or completionSetCount.

Hope this helps.
# January 5, 2006 1:16 PM

Shahed Khan said:

# January 14, 2006 7:10 PM

Shahed Khan said:

# January 19, 2006 7:32 PM

www.ChrisMay.org said:

# September 18, 2006 2:45 PM
New Comments to this post are disabled