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();
    }

Friday, October 31, 2008

Custom AutoComplete 1: Mutiple rows message for each Item

AjaxControlToolkit AutoComplete will pop up the result list according to what you typed. Each items of result list contains one-line text. When we type like "Vin", it will return "Vince", "Vincent", "Vint" in the result list. But if we want to append some detail to an additional line within the an item, how we can get that? For example, When we type "Vin", we hope it will result the related name and age in an additional line. When we select the item, it will return just name as the value. (See the thumbnail)


<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="dd" OnClientItemSelected="itemSelected"
BehaviorID="AutoCompleteEx"
ID="autoComplete1"
TargetControlID="myTextBox"
ServicePath="AutoComplete.asmx"
ServiceMethod="GetCompletionList"
MinimumPrefixLength="2"
CompletionInterval="1000"
EnableCaching="true"
CompletionSetCount="8"
CompletionListCssClass="autocomplete_completionListElement"
CompletionListItemCssClass="autocomplete_listItem"
CompletionListHighlightedItemCssClass="autocomplete_highlightedListItem"
DelimiterCharacters=";, :">
</ajaxToolkit:AutoCompleteExtender>


</form>
</body>
<script type="text/javascript">
function itemSelected(ev)
{
var index=$find("AutoCompleteEx")._selectIndex;
var dd=$find("AutoCompleteEx").get_completionList().childNodes[index]._value;
$find("AutoCompleteEx").get_element().value=dd;
}
function dd()
{
var comletionList=$find("AutoCompleteEx").get_completionList();
for(i=0;i<comletionList.childNodes.length;i++)
{

var _value=comletionList.childNodes[i]._value;
comletionList.childNodes[i]._value=_value.substring(_value.lastIndexOf('|')+1);// parse id to _value

_value=_value.substring(0,_value.lastIndexOf('|'));
comletionList.childNodes[i].innerHTML=_value.replace('|','<br/>');
}

}
</script>


WebMethod in AutoComplete.asmx:

[WebMethod]
public string[] GetCompletionList(string prefixText, int count)
{
    System.Threading.Thread.Sleep(2000);
    if (count == 0)
    {
        count = 10;
    }

    if (prefixText.Equals("xyz"))
    {
        return new string[0];
    }

    Random random = new Random();
    List<string> items = new List<string>(count);


    for (int i = 0; i < count; i++)
    {
        char c1 = (char)random.Next(65, 90);
        char c2 = (char)random.Next(97, 122);
        char c3 = (char)random.Next(97, 122);
        int id = i;
        int age = random.Next(18, 70);
        items.Add(prefixText + c1 + c2 + c3 +"|"+age.ToString()+"|"+id.ToString());
    }

    return items.ToArray();
}


ID, Name and Age will be returned from web method to the client. JavaScript will change the format of result and set the value as ID. When you select the item, the value will be as the text of TextBox.

In this way, we can even append an image in font of each item. I will intoduce about "AutoComplete with Image" next time.

Monday, October 27, 2008

How to display Progress bar when the first time page load

 

Last time, I introduced the ModalUpdateProgress, which is designed for postback. Then how to show "page loading" when the first time page load,  we need to find another way to achieve it.

We hope the page will not flash too much time. It will be better if the page shows "page loading" with percent progress untill the page loaded and rendered.

 

    protected void Page_Load(object sender, EventArgs e)
    {
        showPageLoad();
        //do somthing


    }
    private void showPageLoad()
    {
        int i=0;
        Response.Write("<div id='divTitle'>Loading(<span id='message'>0%</span>)</div>");
        Response.Flush();
        for(i=5;i<=100;i=i+5)
        {
            System.Threading.Thread.Sleep(200);// any codes can be typed here
            outputflash(i.ToString() + "%");
            Response.Flush();
        }
    }
    private void removePageLoad()
    {
        ScriptManager.RegisterStartupScript(Page, this.GetType(), "deleteLoading", "var d = document.getElementById('divTitle');d.parentNode.removeChild(d);", true);

    }
    private void outputflash(string value)
    {       
      Response.Write("<script type='text/javascript'>document.getElementById('message').innerHTML='" + value + "';</script>");

    }

 

How to make ModalUpdate Progress Bar on page?

1. Generate the ModalUpdate Progress bar when a button is triggered.

UpdateProgress can help us to build "page loading" progress on the page. But some times we want the page loading is popped up above the page and disable the background of page. Check the below image. In this way, we can use AjaxControlToolkit ModalPopup to achieve it.

1

Try the below sample code to achieve Modalupdate progress.

Firstly, you need download & install AjaxControlToolKits : http://www.asp.net/AJAX/AjaxControlToolkit/Samples/Default.aspx

<%@ Register
Assembly="AjaxControlToolkit"
Namespace="AjaxControlToolkit"
TagPrefix="ajaxToolkit" %>

<head runat="server">
<title>Untitled Page</title>
<style>
.modalBackground {
background-color:Gray;
filter:alpha(opacity=70);
opacity:0.7;

}

.modalPopup {
background-color:#ffffdd;
border-width:3px;
border-style:solid;
border-color:Gray;
padding:3px;
width:250px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<ajaxToolkit:ToolkitScriptManager runat="Server" ID="ScriptManager1" />
<script type="text/javascript">
function showPopup() {
var modalPopupBehavior = $find('programmaticModalPopupBehavior');
modalPopupBehavior.show();
}
function hidepopup()
{
var modalPopupBehavior = $find('programmaticModalPopupBehavior');
modalPopupBehavior.hide();
}
</script>

<asp:Button ID="loginButton" runat="server" Text="login" OnClientClick="showPopup()"
onclick="loginButton_Click" /><br />

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
Put the control which needs to update here, such as GridView.

</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="loginButton" EventName="Click"/>
</Triggers>
</asp:UpdatePanel>

<br />


<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:25px;width:85px;padding:10px">
<div id='messagediv' style="text-align:center">Loading...</div>

</asp:Panel>
</form>
</body>
    protected void loginButton_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(2000);//For testing.
programmaticModalPopup.Hide();

}

(You can change the css style or add an image into programmaticPopup instead of "Loading".)

With this sample, we need assign the specific control to raise the ModalUpdateProgress.

2. How can we pop up the ModalUpdateProgress bar while each request is posted and each control is triggered?

On assuming that you have a GridView. And when the request is from GridView, it will generate popup panel to display "loading".

<script type="text/javascript">
function pageLoad()
{
$find('modalbehavior').hide();
}
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(
function(sender, e)
{
if (e.get_postBackElement().id == "<%= GridView1.ClientID %>") // This line can make sure only the request from GridView1 will present popup panel, you can change it to other control client id.
{
$find('modalbehavior').show();
}
});

</script>

Beside this code, you need a ModalPopup to show the Loading message.

<style>
.modalBackground {
background-color:Gray;
filter:alpha(opacity=70);
opacity:0.7;

}

.modalPopup {
background-color:#ffffdd;
border-width:3px;
border-style:solid;
border-color:Gray;
padding:3px;
width:250px;
}
<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:25px;width:85px;padding:10px">
<div id='messagediv' style="text-align:center">Loading...</div>

</asp:Panel>