суббота, 9 апреля 2011 г.

Asp.net. AutoPostBack TextBox using UpdatePanel

First of all, i need to say, that this programming method is not really correct. Preferable method is to use some  javascript frameworks like "JQuery" or "Prototype" and .ashx handler for retrieving markup.
Begin with creation of usercontrol called "ListBoxFilterControl.ascx". It contains a UpdatePanel, ListBox control and TextBox control. ListBox contain some data, user inputs some text into TextBox and ListBox's data filtered, depending on inputed text.

Not Filtered ListBox
Filtered TextBox   
After creation of "ListBoxFilterControl.ascx", we need to modify "Default.aspx" file like this
  • Register user control at a page adding a line 
<%@ Register Src="~/ListBoxFilterControl.ascx" TagPrefix="uc" TagName="AutoPostBackControl" %>
  • Add ScriptManager and created usercontrol  
<asp:ScriptManager ID="sm" runat="server"> </asp:ScriptManager> <div> <uc:AutoPostBackControl ID="ap1" runat="server" /> </div>

There are some  "bad things" in current solution. UpdatePanel by default posts data everytime, when user inputs a symbol. In a high load projects this is unacceptable. That's why  this control post a inputed text with some delay. In this example, it is approximately two seconds after the user finishes typing.

Code of "ListBoxFilterControl.ascx":

<asp:UpdatePanel ID="up" runat="server" UpdateMode="Conditional">


<contenttemplate>
<div style="width: 100%;">
<div style="float: left; width: 250px;margin-left:20px;">
ListBox:
<asp:ListBox ID="lbFirst" runat="server" Rows="5" AutoPostBack="true" DataTextField="value"
DataValueField="key" SelectionMode="Single" Width="250px"></asp:ListBox>
</div>
</div>
<div style="width: 500px;margin-left:20px;margin-top:5px;">
<b>
Search:
</b>
</div>
<div style="width: 500px;padding-left:20px;margin-top:5px;">
<asp:TextBox CssClass="mp0" ID="txtFilter" onblur="return false;" onfocus="update(this);" runat="server" Width="100px" OnTextChanged="txtFilter_textChanged" ></asp:TextBox>
</div>
</contenttemplate>
<triggers>
<asp:AsyncPostBackTrigger ControlID="txtFilter" EventName="TextChanged"/>
</triggers>
</asp:UpdatePanel>
<script language="javascript" type="text/javascript">

function update(o) {
var t = o.value;
doSetCaretPosition(o, t.length);
}


function doSetCaretPosition(oField, iCaretPos) {

// IE Support
if (document.selection) {

// Set focus on the element
oField.focus();

// Create empty selection range
var oSel = document.selection.createRange();

// Move selection start and end to 0 position
oSel.moveStart('character', -oField.value.length);

// Move selection start and end to desired position
oSel.moveStart('character', iCaretPos);
oSel.moveEnd('character', 0);
oSel.select();
}

// Firefox support
else if (oField.selectionStart || oField.selectionStart == '0') {
oField.selectionStart = iCaretPos;
oField.selectionEnd = iCaretPos;
oField.focus();
}
}

function StTimeout(objName) {
document.getElementById('hTimeout').value = Date();
setTimeout('chkTimeout(\'' + objName + '\',\'\')', 2000);
}

function chkTimeout(objName) {
today = Number(new Date());
var pastDate = Date.parse(document.getElementById('hTimeout').value);
if (Math.ceil(today - pastDate) < 2000) {
//document.getElementById('hTimeout').value = Date();
return false;
}
else {
document.getElementById('hTimeout').value = Date();
__doPostBack(objName, '');
}
}

</script>
<input type="hidden" id="hTimeout" name="hTimeout" />

Code of "ListBoxFilterControl.ascx.cs"
using System;

using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class ListBoxFilterControl : System.Web.UI.UserControl
{
Dictionary<int, string> _First;
public Dictionary<int, string> First
{
get
{
if (_First == null)
_First = new Dictionary<int, string>();
return _First;
}

set
{
_First = value;
}
}

private void SetToViewState(Dictionary<int, string> dic, string ViewStateName)
{
ViewState[ViewStateName] = dic;
}

private Dictionary<int, string> GetFromViewState(string ViewStateName)
{
if (ViewState[ViewStateName] != null)
return ViewState[ViewStateName] as Dictionary<int, string>;
return null;
}

protected void Page_Load(object sender, EventArgs e)
{
txtFilter.Attributes.Add("onKeyUp", string.Format(@"javascript:setTimeout('StTimeout(\'{0}\')', 500)", txtFilter.UniqueID));
if (!Page.IsPostBack)
{
if (First != null && First.Count > 0)
SetToViewState(First, "First");
InitLists();
}
else
{
First = GetFromViewState("First");
}
}

protected void txtFilter_textChanged(object sender, EventArgs e)
{
lbFirst.Items.Clear();
First = GetFromViewState("First");
if (!string.IsNullOrEmpty(txtFilter.Text))
First = First.Where(d => d.Value.Contains(txtFilter.Text)).ToDictionary(d => d.Key, d => d.Value);

lbFirst.DataSource = First;
lbFirst.DataBind();
txtFilter.Focus();

}
protected void InitLists()
{
lbFirst.Items.Clear();
if (First != null && First.Count > 0)
{
if (!string.IsNullOrEmpty(txtFilter.Text))
First = First.Where(d => d.Value.Contains(txtFilter.Text)).ToDictionary(d => d.Key, d => d.Value);

lbFirst.DataSource = First;
lbFirst.DataBind();
}
}
}

Code of "Default.aspx":

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register Src="~/ListBoxFilterControl.ascx" TagPrefix="uc" TagName="AutoPostBackControl" %>
.......
<asp:ScriptManager ID="sm" runat="server"></asp:ScriptManager>
<div><uc:AutoPostBackControl ID="ap1" runat="server" /> </div>
..... 

Code of "Default.aspx.cs": 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Dictionary<int, string> Dict = new Dictionary<int, string>();
Dict.Add(0, "zero");
Dict.Add(1, "one");
Dict.Add(2, "two");
Dict.Add(3, "three");
ap1.First = Dict;
}
}
}

 

Комментариев нет:

Отправить комментарий