Thursday, November 27, 2008

Build a Combobox in ASP.Net

As we all known, DropDownList in ASP.Net is totally different from Combobox in WinForm. However, sometimes, we hope we are able to input some words in DropDownList in ASP.Net, and the related item will be hightlighten so that we can get the functionality of Combobox in WinForm.


Fortunately, AjaxControlToolkit provides ListSearch control for us to achieve this(http://www.asp.net/AJAX/AjaxControlToolkit/Samples/ListSearch/ListSearch.aspx). But we have to build two controls to populate the functionality and type the key words above the select control.


It's still different from Combobox in Winform. We hope we can type the words inside DropDownList and the related item will be returned in the list as the below pic.
How can we achieve that?
I rebuild the whole select control with HTML code and Css so that I can input text inside select control.


Default.aspx:

<!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>combobox</title>
    <link href="ListSearch.css" rel="stylesheet" type="text/css" />
</head>

<script type="text/javascript">
    var dropShow = false
    var currentID
    function dropdown(el) {
        if (dropShow) {
            dropFadeOut()
        } else {
            currentID = el
            el.style.visibility = "visible"
            dropFadeIn()
        }
    }
    function dropFadeIn() {//select box fade in
        if (currentID.filters.alpha.opacity < 100) {
            currentID.filters.alpha.opacity += 20
            fadeTimer = setTimeout("dropFadeIn()", 50)
        } else {
            dropShow = true
            clearTimeout(fadeTimer)
        }
    }
    function dropFadeOut() {//select box fade out
        if (currentID.filters.alpha.opacity > 0) {
            clearTimeout(fadeTimer)
            currentID.filters.alpha.opacity -= 20
            fadeTimer = setTimeout("dropFadeOut()", 50)
        } else {
            dropShow = false
            currentID.style.visibility = "hidden"
        }
    }
    function dropdownHide() {
        if (dropShow) {
            dropFadeOut()
            dropShow = false
        }
    }
    function hiLight(el) {//highlight place
        if (dropShow) {
            for (i = 0; i < el.parentElement.childNodes.length; i++) {
                el.parentElement.childNodes(i).className = "link_record0"
            }
            el.className = "link_record1"
        }
    }
    function CheckMe(el) {//replace with the selected item
        document.all.text1.value = el.innerText

    }
    document.onclick = dropdownHide


    function listsearch() {
        if (dropShow) {

        } else {
            currentID = value1
            value1.style.visibility = "visible"
            dropFadeIn()
        }
        var word = document.all.text1.value;
        var l;
        var childsnum = value1.childNodes.length;
        for (l = 0; l < childsnum; l++) {
            var s = value1.childNodes[l].innerText;

            if (s.substring(0, word.length) == word)
                hiLight(value1.childNodes[l]);

        }

    }
</script>

<body text="#000000">
    <form id="form1" runat="server">
    <table>
        <tr>
            <td>
                <div class="link_box" onselectstart="return false" style="width: 98%;">
                    <div class="link_head" onclick="dropdown(value1)">
                        <table height="100%" cellspacing="0" cellpadding="0" width="100%" border="0">
                            <tr>
                                <td>
                                    <div class="link_text">
                                        <nobr><input id="text1" type="text" onkeyup="listsearch()"></input></nobr>
                                    </div>
                                </td>
                                <td align="right" width="22">
                                    <div onmouseup="this.className='link_arrow0'" class="link_arrow0" onmousedown="this.className='link_arrow1'"
                                        onkeypress="this.className='link_arrow0'">
                                        6</div>
                                </td>
                            </tr>
                        </table>
                    </div>
                    <div class="link_value" id="value1" style="width: 500px; height: 300px">
                        <div class="link_record0" onmouseover="hiLight(this)" onclick="CheckMe(this);document.all.form1.city.value=this.innerText">
                            <label>
                                attach</label></div>
                        <div class="link_record0" onmouseover="hiLight(this)" onclick="CheckMe(this);document.all.form1.city.value=this.innerText">
                            <label>
                                bea</label></div>
                        <div class="link_record0" onmouseover="hiLight(this)" onclick="CheckMe(this);document.all.form1.city.value=this.innerText">
                            <label>
                                free</label></div>
                        <div class="link_record0" onmouseover="hiLight(this)" onclick="CheckMe(this);document.all.form1.city.value=this.innerText">
                            <label>
                                jump</label></div>
                        <div class="link_record0" onmouseover="hiLight(this)" onclick="CheckMe(this);document.all.form1.city.value=this.innerText">
                            <label>
                                lumb</label></div>
                        <div class="link_record0" onmouseover="hiLight(this)" onclick="CheckMe(this);document.all.form1.city.value=this.innerText">
                            <label>
                                luppy</label></div>
                    </div>
                </div>
            </td>
            <td>
                <input type="hidden" value="Please Select" name="city">
                <input type="submit" value="ok">
            </td>
        </tr>
    </table>
    </form>
</body>
</html>


ListSearch.css:

BODY {
FONT: 12px
}
TD {
FONT: 12px
}
DIV {
FONT: 12px
}
LABEL {
PADDING-RIGHT: 0px; PADDING-LEFT: 4px; PADDING-BOTTOM: 0px; PADDING-TOP: 3px; HEIGHT: 19px
}
.link_box {
CURSOR: default; TEXT-ALIGN: left;
}
.link_head {
BORDER-RIGHT: 2px inset; BORDER-TOP: 2px inset; BORDER-LEFT: 2px inset; WIDTH: 100%;
BORDER-BOTTOM: 2px inset; HEIGHT: 23px
}
.link_text {
PADDING-LEFT: 2px; BACKGROUND: #fff
}
.link_arrow0 {
BORDER-RIGHT: 2px outset; BORDER-TOP: 2px outset; BACKGROUND: buttonface;
FONT: 14px marlett; BORDER-LEFT: 2px outset; WIDTH: 22px;
BORDER-BOTTOM: 2px outset; HEIGHT: 19px; TEXT-ALIGN: center
}
.link_arrow1 {
BORDER-RIGHT: buttonshadow 1px solid; PADDING-RIGHT: 0px;
BORDER-TOP: buttonshadow 1px solid; PADDING-LEFT: 2px;
BACKGROUND: buttonface; PADDING-BOTTOM: 0px; FONT: 14px marlett;
BORDER-LEFT: buttonshadow 1px solid; WIDTH: 22px; PADDING-TOP: 2px;
BORDER-BOTTOM: buttonshadow 1px solid; HEIGHT: 19px; TEXT-ALIGN: center
}
.link_value {
BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; FILTER: alpha(opacity:0);
VISIBILITY: hidden; OVERFLOW-X: hidden; OVERFLOW: auto; BORDER-LEFT: 1px solid;
BORDER-BOTTOM: 1px solid; POSITION: absolute
}
.link_record0 {
BORDER-TOP: #eee 1px solid; PADDING-LEFT: 2px; BACKGROUND: #fff;
WIDTH: 100%; COLOR: #000; HEIGHT: 20px
}
.link_record1 {
BORDER-TOP: #047 1px solid; PADDING-LEFT: 2px; BACKGROUND: #058;
WIDTH: 100%; COLOR: #fe0; HEIGHT: 20px
}


The sample is based on native code. I plan to build it by ASP.Net Ajax ScriptControl model in the future.

Monday, November 24, 2008

How to disable the dates which are less than the current day?

AjaxControlToolkit Calendar is a very DatePicker for us. Sometimes, the customers hope some specific date in Calendar should be disabled or hidden so that we can not select these dates.

For example,
-- how to disable the dates which are less than the current date?
-- how to disable the dates other than sunday?

Actually, you can modify the original CalendarBehavior.js to achieve it.

1.Please go to CalendarBehavior.js in AjaxControlToolkit original project.
2.Please use the below code instead of section ‘case "days": ' in function _cell_onclick: case "day":

var _currentDay=new Date();
if(target.date.getDate()>=_currentDay.getDate())
{
this.set_selectedDate(target.date);
this._switchMonth(target.date);
this._blur.post(true);
this.raiseDateSelectionChanged();
}
break;

3.If you want to change the dates' style which are less than current day, you can use other css class on the related date cell when the calendar was created in _performLayout method.
The below code can be used to apply the different css calss on the related date cell in _performLayout method.
Sys.UI.DomElement.addCssClass(dayCell.parentNode, this._getCssClass(dayCell.date, 'name'));

4.And then please rebuild the project and add it as reference again.

Thursday, November 20, 2008

ModalPopup in MasterPage

In aspx page, we can handle a ModalPopup to work by binding related target properties. If ModalPopup is in MasterPage, some engineers encountered problem on defining TargetControlID, OKControl or CancelControl, since these target controls are in the child page so that we can't bind the target control id to ModalPopup directly.

The solution of it is using FindControl in child page to bind TargetControlID on ModalPopup dynamically. But I don't think it is a convenient way.

Here, I suggest you use client behavior method to achieve it.

MasterPage:

<head runat="server">
    <title></title>
    <style>
        .modalBackground
        {
            background-color: Gray;
            filter: alpha(opacity=0);
            opacity: 0;
        }
        .modalPopup
        {
            background-color: #ffffdd;
            border-width: 3px;
            border-style: solid;
            border-color: Gray;
            padding: 3px;
            width: 250px;
        }
    </style>
    <asp:ContentPlaceHolder ID="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form id="form1" runat="server">
        <ajaxtoolkit:toolkitscriptmanager runat="Server" id="ScriptManager1" >
        </ajaxtoolkit:toolkitscriptmanager>
        <script type="text/javascript">


            function showPopup() {
                var modalPopupBehavior = $find('programmaticModalPopupBehavior');
                modalPopupBehavior.show();

            }

            function hidePopup() {
                var modalPopupBehavior = $find('programmaticModalPopupBehavior');
                modalPopupBehavior.hide();

            }
        </script>
        <asp:Button runat="server" ID="hiddenTargetControlForModalPopup" style="display:none"/>
        <ajaxtoolkit:ModalPopupExtender runat="server" ID="programmaticModalPopup"
            BehaviorID="programmaticModalPopupBehavior"
            TargetControlID="hiddenTargetControlForModalPopup"
            PopupControlID="programmaticPopup"
            BackgroundCssClass="modalBackground"
            DropShadow="True" 
            RepositionMode="RepositionOnWindowScroll" >
        </ajaxtoolkit:ModalPopupExtender>

        <asp:Panel runat="server" CssClass="modalPopup" ID="programmaticPopup" style="background-color:##FFFFCC;display:none;height:125px;width:225px;padding:10px">
            I'm the ModalPopup in MasterPage

            <input id="Button1" type="button" value="OK" onclick="hidePopup()" />
        </asp:Panel>

        <asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
       
        </asp:ContentPlaceHolder>

    </form>
</body>


Child Page:


<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
    <asp:Button ID="Button1" runat="server" Text="I'm a Button in child page" OnClientClick="showPopup();return false;" />
</asp:Content>

Monday, November 3, 2008

Custom AutoComplete 2: AutoComplete with Image

Following the approach from the last article, we can use the same one to build an AjaxControlToolkit AutoComplete with image or other plug-in elements in front of each item in CompletedList. Every word is in the below code.







<body>
    <form id="form1" runat="server">
        <ajaxToolkit:ToolkitScriptManager runat="server" ID="ScriptManager1" />

           <asp:TextBox runat="server" ID="myTextBox" Width="300" autocomplete="off" />
            <ajaxToolkit:AutoCompleteExtender
                runat="server"  OnClientPopulated="onClientPopulated" OnClientItemSelected="itemSelected"
                BehaviorID="AutoCompleteEx"
                ID="autoComplete1"
                TargetControlID="myTextBox"
                ServicePath="AutoComplete.asmx"
                ServiceMethod="GetCompletionList3"
                MinimumPrefixLength="2"
                CompletionInterval="1000"

                CompletionSetCount="8"
                CompletionListCssClass="autocomplete_completionListElement"
                CompletionListItemCssClass="autocomplete_listItem"
                CompletionListHighlightedItemCssClass="autocomplete_highlightedListItem"
                DelimiterCharacters=";, :">
               
            </ajaxToolkit:AutoCompleteExtender>

    </form>
       <script type="text/javascript">
function itemSelected(ev)
{

    var index=$find("AutoCompleteEx")._selectIndex;
    if(index!=-1)
    $find("AutoCompleteEx").get_element().value=$find("AutoCompleteEx").get_completionList().childNodes[index]._value;

}
function onClientPopulated(sender,e)
{

    var comletionList=$find("AutoCompleteEx").get_completionList();
    for(i=0;i<comletionList.childNodes.length;i++)
    {   
        var _value=comletionList.childNodes[i]._value;       
        var text=_value[0];
        var moreText=_value[1];
        var imgeUrl= _value[2];
        comletionList.childNodes[i]._value=text;
        comletionList.childNodes[i].innerHTML="<table><tr><td><img src="+imgeUrl+" /></td><td>"+text+"<br />"+moreText+"</td></tr></table>";

    }
   
}




</script>
</body>


Web Method:


[WebMethod]
    public string[] GetCompletionList3(string prefixText, int count)
    {
        JavaScriptSerializer jss = new JavaScriptSerializer();
        List<string> items = new List<string>(3);
        for (int i = 0; i < 3; i++)
        {
            object[] item = new object[] { prefixText + "text"+i.ToString(), "moreText","images/demo.gif" };
            items.Add(jss.Serialize(item));
        }
        return items.ToArray();
    }