|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionBy default, the At the moment, Inherit the AutoCompletePropertiesThe first step is to create C# classes for the new control namespace CustomAtlas.Controls
{
public class CustomAutoCompleteProperties : AutoCompleteProperties
{
public string SeparatorChar
{
get
{
object obj = base.ViewState["SeparatorChar"];
if (obj != null) return (string)obj;
else return ",";
}
set
{
base.ViewState["SeparatorChar"] = value;
base.OnChanged(EventArgs.Empty);
}
}
public string CssList
{
get
{
object obj = base.ViewState["CssList"];
if (obj != null) return (string)obj;
else return String.Empty;
}
set
{
base.ViewState["CssList"] = value;
base.OnChanged(EventArgs.Empty);
}
}
public string CssItem
{
get
{
object obj = base.ViewState["CssItem"];
if (obj != null) return (string)obj;
else return String.Empty;
}
set
{
base.ViewState["CssItem"] = value;
base.OnChanged(EventArgs.Empty);
}
}
public string CssHoverItem
{
get
{
object obj = base.ViewState["CssHoverItem"];
if (obj != null) return (string)obj;
else return String.Empty;
}
set
{
base.ViewState["CssHoverItem"] = value;
base.OnChanged(EventArgs.Empty);
}
}
}
}
The Inherit the AutoCompleteExtenderFirst step done, we continue with the Extender. In this case, we inherit from the namespace CustomAtlas.Controls
{
public class CustomAutoCompleteExtender : AutoCompleteExtender
{
protected override void RenderScript(
Microsoft.Web.Script.ScriptTextWriter writer, Control targetControl)
{
// get our CustomAutoCompleteProperties
CustomAutoCompleteProperties cacp =
(CustomAutoCompleteProperties)
base.GetTargetProperties(targetControl);
if ((cacp != null) && cacp.Enabled)
{
// check if the ServicePath is set
string _ServicePath = cacp.ServicePath;
if (_ServicePath == String.Empty)
{
_ServicePath = this.ServicePath;
}
if (_ServicePath == String.Empty)
{
throw new InvalidOperationException("The ServicePath " +
"must be set for AutoCompleteBehavior");
}
// check if the ServiceMethod is set
string _ServiceMethod = cacp.ServiceMethod;
if (_ServiceMethod == String.Empty)
{
_ServiceMethod = this.ServiceMethod;
}
if (_ServiceMethod == String.Empty)
{
throw new InvalidOperationException("The ServiceMethod " +
"must be set for AutoCompleteBehavior");
}
// search for the completion list control if an ID was supplied
Control c = null;
string drp = this.DropDownPanelID;
if (drp != String.Empty)
{
c = this.NamingContainer.FindControl(drp);
if (c == 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(_ServicePath));
writer.WriteAttributeString("serviceMethod", _ServiceMethod);
if (c != null)
writer.WriteAttributeString("completionList", c.ClientID);
writer.WriteAttributeString("minimumPrefixLength",
cacp.MinimumPrefixLength.ToString());
writer.WriteAttributeString("separatorChar",
cacp.SeparatorChar);
writer.WriteAttributeString("cssList", cacp.CssList);
writer.WriteAttributeString("cssItem", cacp.CssItem);
writer.WriteAttributeString("cssHoverItem",
cacp.CssHoverItem);
writer.WriteEndElement();
}
}
}
}
Implementing the custom AutoCompleteBehaviorNow that the control is ready, we have only to manage the client-side code to send the right value to the Web Service (the comma-separated word) and to apply our custom CSS style. Searching for the Type.registerNamespace('Custom.UI');
Custom.UI.AutoCompleteBehavior = function() {
Custom.UI.AutoCompleteBehavior.initializeBase(this);
var _appURL;
var _serviceURL;
var _serviceMethod;
var _separatorChar = ',';
var _minimumPrefixLength = 3;
var _cssList;
var _cssItem;
var _cssHoverItem;
var _completionSetCount = 10;
var _completionInterval = 1000;
var _completionListElement;
var _popupBehavior;
var _timer;
var _cache;
var _currentPrefix;
var _selectIndex;
var _focusHandler;
var _blurHandler;
var _keyDownHandler;
var _mouseDownHandler;
var _mouseUpHandler;
var _mouseOverHandler;
var _tickHandler;
this.get_appURL = function() {
return _appURL;
}
this.set_appURL = function(value) {
_appURL = value;
}
this.get_completionInterval = function() {
return _completionInterval;
}
this.set_completionInterval = function(value) {
_completionInterval = value;
}
this.get_completionList = function() {
return _completionListElement;
}
this.set_completionList = function(value) {
_completionListElement = value;
}
this.get_completionSetCount = function() {
return _completionSetCount;
}
this.set_completionSetCount = function(value) {
_completionSetCount = value;
}
this.get_minimumPrefixLength = function() {
return _minimumPrefixLength;
}
this.set_minimumPrefixLength = function(value) {
_minimumPrefixLength = value;
}
this.get_separatorChar = function() {
return _separatorChar;
}
this.set_separatorChar = function(value) {
_separatorChar = value;
}
this.get_serviceMethod = function() {
return _serviceMethod;
}
this.set_serviceMethod = function(value) {
_serviceMethod = value;
}
this.get_serviceURL = function() {
return _serviceURL;
}
this.set_serviceURL = function(value) {
_serviceURL = value;
}
/* styles */
this.get_cssList = function() {
return _cssList;
}
this.set_cssList = function(value) {
_cssList = value;
}
this.get_cssItem = function() {
return _cssItem;
}
this.set_cssItem = function(value) {
_cssItem = value;
}
this.get_cssHoverItem = function() {
return _cssHoverItem;
}
this.set_cssHoverItem = function(value) {
_cssHoverItem = value;
}
this.dispose = function() {
if (_timer) {
_timer.tick.remove(_tickHandler);
_timer.dispose();
}
var element = this.control.element;
element.detachEvent('onfocus', _focusHandler);
element.detachEvent('onblur', _blurHandler);
element.detachEvent('onkeydown', _keyDownHandler);
_completionListElement.detachEvent('onmousedown', _mouseDownHandler);
_completionListElement.detachEvent('onmouseup', _mouseUpHandler);
_completionListElement.detachEvent('onmouseover', _mouseOverHandler);
_tickHandler = null;
_focusHandler = null;
_blurHandler = null;
_keyDownHandler = null;
_mouseDownHandler = null;
_mouseUpHandler = null;
_mouseOverHandler = null;
Sys.UI.AutoCompleteBehavior.callBaseMethod(this, 'dispose');
}
this.getDescriptor = function() {
var td = Custom.UI.AutoCompleteBehavior.callBaseMethod(this,
'getDescriptor');
td.addProperty('completionInterval', Number);
td.addProperty('completionList', Object, false,
Sys.Attributes.Element, true);
td.addProperty('completionSetCount', Number);
td.addProperty('minimumPrefixLength', Number);
td.addProperty('separatorChar', String);
td.addProperty('cssList', String);
td.addProperty('cssItem', String);
td.addProperty('cssHoverItem', String);
td.addProperty('serviceMethod', String);
td.addProperty('serviceURL', String);
td.addProperty('appURL', String);
return td;
}
this.initialize = function() {
Custom.UI.AutoCompleteBehavior.callBaseMethod(this, 'initialize');
_tickHandler = Function.createDelegate(this, this._onTimerTick);
_focusHandler = Function.createDelegate(this, this._onGotFocus);
_blurHandler = Function.createDelegate(this, this._onLostFocus);
_keyDownHandler = Function.createDelegate(this, this._onKeyDown);
_mouseDownHandler = Function.createDelegate(this,
this._onListMouseDown);
_mouseUpHandler = Function.createDelegate(this, this._onListMouseUp);
_mouseOverHandler = Function.createDelegate(this,
this._onListMouseOver);
_timer = new Sys.Timer();
_timer.set_interval(_completionInterval);
_timer.tick.add(_tickHandler);
var element = this.control.element;
element.autocomplete = "off";
element.attachEvent('onfocus', _focusHandler);
element.attachEvent('onblur', _blurHandler);
element.attachEvent('onkeydown', _keyDownHandler);
var elementBounds = Sys.UI.Control.getBounds(element);
if (!_completionListElement) {
_completionListElement = document.createElement('DIV');
document.body.appendChild(_completionListElement);
}
// apply styles
var completionListStyle = _completionListElement.style;
if ( _cssList != '' )
{
_completionListElement.className = _cssList;
}
else
{
completionListStyle.backgroundColor = 'window';
completionListStyle.color = 'windowtext';
completionListStyle.border = 'solid 1px buttonshadow';
completionListStyle.cursor = 'default';
}
// default styles
completionListStyle.unselectable = 'unselectable';
completionListStyle.overflow = 'hidden';
completionListStyle.visibility = 'hidden';
completionListStyle.width = (elementBounds.width - 2) + 'px';
_completionListElement.attachEvent('onmousedown', _mouseDownHandler);
_completionListElement.attachEvent('onmouseup', _mouseUpHandler);
_completionListElement.attachEvent('onmouseover', _mouseOverHandler);
document.body.appendChild(_completionListElement);
var popupControl = new Sys.UI.Control(_completionListElement);
_popupBehavior = new Sys.UI.PopupBehavior();
_popupBehavior.set_parentElement(element);
_popupBehavior.set_positioningMode(Sys.UI.PositioningMode.BottomLeft);
popupControl.get_behaviors().add(_popupBehavior);
_popupBehavior.initialize();
popupControl.initialize();
}
this._hideCompletionList = function() {
_popupBehavior.hide();
_completionListElement.innerHTML = '';
_selectIndex = -1;
}
this._highlightItem = function(item) {
var children = _completionListElement.childNodes;
// non-selecteditems
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (child != item) {
if ( _cssItem != '' )
{
child.className = _cssItem;
}
else
{
child.style.backgroundColor = 'window';
child.style.color = 'windowtext';
}
}
}
// selected item
if ( _cssHoverItem != '' )
{
item.className = _cssHoverItem;
}
else
{
item.style.backgroundColor = 'highlight';
item.style.color = 'highlighttext';
}
}
this._onListMouseDown = function() {
if (window.event.srcElement != _completionListElement) {
this._setText(window.event.srcElement.firstChild.nodeValue);
}
}
this._onListMouseUp = function() {
this.control.focus();
}
this._onListMouseOver = function() {
var item = window.event.srcElement;
_selectIndex = -1;
this._highlightItem(item);
}
this._onGotFocus = function() {
_timer.set_enabled(true);
}
this._onKeyDown = function() {
var e = window.event;
if (e.keyCode == 27) {
this._hideCompletionList();
e.returnValue = false;
}
else if (e.keyCode == Sys.UI.Key.Up) {
if (_selectIndex > 0) {
_selectIndex--;
this._highlightItem(
_completionListElement.childNodes[_selectIndex]);
e.returnValue = false;
}
}
else if (e.keyCode == Sys.UI.Key.Down) {
if (_selectIndex < (_completionListElement.childNodes.length - 1)) {
_selectIndex++;
this._highlightItem(
_completionListElement.childNodes[_selectIndex]);
e.returnValue = false;
}
}
else if (e.keyCode == Sys.UI.Key.Return) {
if (_selectIndex != -1) {
this._setText(_completionListElement.childNodes[_selectIndex].
firstChild.nodeValue);
e.returnValue = false;
}
}
if (e.keyCode != Sys.UI.Key.Tab) {
_timer.set_enabled(true);
}
}
this._onLostFocus = function() {
_timer.set_enabled(false);
this._hideCompletionList();
}
function _onMethodComplete(result, response, context) {
var acBehavior = context[0];
var prefixText = context[1];
acBehavior._update(prefixText, result, true);
}
this._onTimerTick = function(sender, eventArgs) {
if (_serviceURL && _serviceMethod) {
var text = this.control.element.value;
if ( text.lastIndexOf(_separatorChar) > -1 )
{
// found separator char in the text
var pos = text.lastIndexOf(_separatorChar);
pos++;
text = text.substring(pos, (text.length));
text = text.trim();
}
if (text.trim().length < _minimumPrefixLength) {
this._update('', null, false);
return;
}
if (_currentPrefix != text) {
_currentPrefix = text;
if (_cache && _cache[text]) {
this._update(text, _cache[text], false);
return;
}
Sys.Net.ServiceMethod.invoke(_serviceURL, _serviceMethod,
_appURL, { prefixText : _currentPrefix, count:
_completionSetCount }, _onMethodComplete, null,
null, null, [ this, text ]);
}
}
}
this._setText = function(text) {
_timer.set_enabled(false);
_currentPrefix = text;
if (Sys.UI.TextBox.isInstanceOfType(this.control)) {
this.control.set_text(text);
}
else {
var currentValue = this.control.element.value;
if ( currentValue.lastIndexOf(_separatorChar) > -1 )
{
// found separator char in the text
var pos = currentValue.lastIndexOf(_separatorChar);
pos++;
currentValue = currentValue.substring(0, pos) + text;
}
else
{
// no separator char found
currentValue = text;
}
this.control.element.value = currentValue;
}
this._hideCompletionList();
}
this._update = function(prefixText, completionItems, cacheResults) {
if (cacheResults) {
if (!_cache) {
_cache = { };
}
_cache[prefixText] = completionItems;
}
_completionListElement.innerHTML = '';
_selectIndex = -1;
if (completionItems && completionItems.length) {
for (var i = 0; i < completionItems.length; i++) {
var itemElement = document.createElement('div');
itemElement.appendChild(
document.createTextNode(completionItems[i]));
itemElement.__item = '';
if ( _cssItem != '' )
{
itemElement.className = _cssItem;
}
else
{
var itemElementStyle = itemElement.style;
itemElementStyle.padding = '1px';
itemElementStyle.textAlign = 'left';
itemElementStyle.textOverflow = 'ellipsis';
itemElementStyle.backgroundColor = 'window';
itemElementStyle.color = 'windowtext';
}
_completionListElement.appendChild(itemElement);
}
_popupBehavior.show();
}
else {
_popupBehavior.hide();
}
}
}
Custom.UI.AutoCompleteBehavior.registerSealedClass(
'Custom.UI.AutoCompleteBehavior', Sys.UI.Behavior);
Sys.TypeDescriptor.addType('script', 'autoComplete',
Custom.UI.AutoCompleteBehavior);
First, we have to add the four properties created in the Extender class. Now, we are able to use the properties’ values of the control placed in the .aspx page container. Searching inside the code, there is a function var text = this.control.element.value;
if ( text.lastIndexOf(_separatorChar) > -1 )
{
// found separator char in the text, choosing the right word
var pos = text.lastIndexOf(_separatorChar);
pos++;
text = text.substring(pos, (text.length));
text = text.trim();
}
Now, when the user types a value in the text box, the Like a standard, I use to save .js code into scriptLibrary folder. Let’s try itThe situation: AutoCompleteBehavior.js saved into the scriptLibrary folder, CustomAutoCompleteProperties.cs and CustomAutoCompleteExtender.cs saved into the App_Code folder... we are ready to try it. Create a new .aspx file, and add a reference to the <%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register Namespace="CustomAtlas.Controls" TagPrefix="customAtlas" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>CustomAutoCompleteExtender</title>
<link href="StyleSheet.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<atlas:ScriptManager ID="scriptManager" runat="server">
<Scripts>
<atlas:ScriptReference ScriptName="Custom" />
<atlas:ScriptReference
Path="scriptLibrary/CustomAutoCompleteBehavior.js" />
</Scripts>
</atlas:ScriptManager>
<div>
<asp:TextBox ID="txtSuggestions"
runat="server"></asp:TextBox>
<customAtlas:CustomAutoCompleteExtender
ID="CustomAutoCompleteExtender1" runat="server">
<customAtlas:CustomAutoCompleteProperties
TargetControlID="txtSuggestions"
ServicePath="WebServiceDemo.asmx"
ServiceMethod="GetSuggestions"
MinimumPrefixLength="1"
SeparatorChar=","
CssList="autoCompleteList"
CssItem="autoCompleteItem"
CssHoverItem="autoCompleteHoverItem"
Enabled="true" />
</customAtlas:CustomAutoCompleteExtender>
</div>
</form>
</body>
</html>
Call a demo Web Service (returns the same value written 10 times), digit one word, then comma (comma is the default char), and starting with a new word, a list with suggestions for a new item is shown. Hope this will be helpful.
|
||||||||||||||||||||||