The Problem
Let's assume you have two TextBox
es. The first one has a TextChanged
event attached and AutoPostBack
set to true
. When you edit TextBox1
and move to TextBox2
, the control TextBox2
loses its focus.
Case 1: The normal postback in ASP.NET 2.0 without smart navigation.
The trick is to save the name of the control which received focus at last, and then restore it after postback. There is a hidden field __LASTFOCUS
, and we are going to use it.
First of all, let us go through all "relevant" controls and set the attribute onfocus
to save their name when they receive focus. "Relevant" are controls which potentially can receive focus. Because we do not want to set this attribute to each control explicitly, we just define types of "relevant" controls and enumerate them recursively.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
HookOnFocus(this.Page as Control);
}
private void HookOnFocus(Control CurrentControl)
{
if ((CurrentControl is TextBox) ||
(CurrentControl is DropDownList) ||
(CurrentControl is ListBox) ||
(CurrentControl is Button))
(CurrentControl as WebControl).Attributes.Add(
"onfocus",
"try{document.getElementById('__LASTFOCUS').value=this.id}
catch(e) {}");
if (CurrentControl.HasControls())
foreach (Control CurrentChildControl in CurrentControl.Controls)
HookOnFocus(CurrentChildControl);
}
Add aditional control types in the first if
condition under the function private void HookOnFocus(Control CurrentControl)
.
Now, we need to set focus after the postback. Insert the following JavaScript as a constant in your page:
private const string SCRIPT_DOFOCUS =
@"window.setTimeout('DoFocus()', 1);
function DoFocus()
{
try {
document.getElementById('REQUEST_LASTFOCUS').focus();
} catch (ex) {}
}";
and this statement to Page_Load
:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
HookOnFocus(this.Page as Control);
Page.ClientScript.RegisterStartupScript(
typeof(MyPage),
"ScriptDoFocus",
SCRIPT_DOFOCUS.Replace("REQUEST_LASTFOCUS",
Request["__LASTFOCUS"]),
true);
}
Case 2: A "tiny Postback" inside the UpdatePanel in ASP.NET 2.0 AJAX
The only difference is that setting the focus must happen after each update inside UpdatePanel
. In this case, the script registered using Page.ClientScript.RegisterStartupScript()
will execute only after each global postback. We need to use ScriptManager.RegisterStartupScript()
instead. The Page_Load
will look like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
HookOnFocus(this.Page as Control);
ScriptManager.RegisterStartupScript(
this,
typeof(MyPage),
"ScriptDoFocus",
SCRIPT_DOFOCUS.Replace("REQUEST_LASTFOCUS", Request["__LASTFOCUS"]),
true);
}