We at times come across a requirement where a feature in a web application is supposed to behave similar to that of its windows counterpart. One such requirement is to either maintain the focus on the control that caused a postback or to shift focus to the next control after a postback.
Ryan Farley has two cool articles on Determining the Control that Caused a PostBack and Set Focus to an ASP.NET Control. We will make use of his code to determine the control that caused a postback. We will then build on that code and use LINQ to loop through the controls, find the TabIndex of the control that caused postback and then shift focus to the control having the next TabIndex. I got this idea of using LINQ while reading a forum post and thought that this solution would be worth sharing with others.
In an application where a lot of text fields are involved, we generally see that when a user tabs out of a textbox, some calculation is performed and the calculated value is then displayed back in the textbox. On a page not powered with ASP.NET AJAX, the desired behavior is to display the calculated value in the textbox and shift the focus to the next one.
In an ASP.NET page, the __doPostBack is used by server controls to cause a postback. If you observe the html markup after a postback, ASP.NET automatically adds two hidden fields (“__EVENTTARGET” and “__EVENTARGUMENT”) and a client-side script method (“__doPostBack”) to the page. The EVENTTARGET is the ID of the control that caused the postback and the EVENTARGUMENT contains any arguments passed that can be accessed on the server. The __doPostBack method sets the values of the hidden fields and causes the form to be submitted to the server. Ryan makes use of the __EVENTTARGET to find the control that caused postback.
Note: Remember that Button and the ImageButton do not use the __doPostBack unless the UseSubmitBehaviour property is set explicitly.
In this sample of ours, I am using a couple of controls on the form to test out our logic. There are a few TextBoxes with AutoPostBack = true which will cause a postback whenever the control looses focus. I also have a couple of Buttons and ImageButton on the page. We will set the TabIndex of each of these controls as shown below:
The markup looks similar to the following:
<form id="form1" runat="server">
<div>
<asp:TextBox ID="TextBox1" runat="server" AutoPostBack="True" TabIndex="1">
</asp:TextBox>
<br />
<asp:TextBox ID="TextBox2" runat="server" AutoPostBack="True" TabIndex="2">
</asp:TextBox>
<br />
<asp:Button ID="Button1" runat="server" Text="Button" TabIndex="3" />
<br />
<asp:Button ID="Button2" runat="server" Text="Button" TabIndex="4" />
<br />
</div>
</form>
The code to set focus to the next control after a postback is given below:
C#
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
WebControl wcICausedPostBack = (WebControl)GetControlThatCausedPostBack(sender as Page);
int indx = wcICausedPostBack.TabIndex;
var ctrl = from control in wcICausedPostBack.Parent.Controls.OfType<WebControl>()
where control.TabIndex > indx
select control;
ctrl.DefaultIfEmpty(wcICausedPostBack).First().Focus();
}
}
protected Control GetControlThatCausedPostBack(Page page)
{
Control control = null;
string ctrlname = page.Request.Params.Get("__EVENTTARGET");
if (ctrlname != null && ctrlname != string.Empty)
{
control = page.FindControl(ctrlname);
}
else
{
foreach (string ctl in page.Request.Form)
{
Control c = page.FindControl(ctl);
if (c is System.Web.UI.WebControls.Button || c is System.Web.UI.WebControls.ImageButton)
{
control = c;
break;
}
}
}
return control;
}
VB.NET
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Page.IsPostBack Then
Dim wcICausedPostBack As WebControl = CType(GetControlThatCausedPostBack(TryCast(sender, Page)), WebControl)
Dim indx As Integer = wcICausedPostBack.TabIndex
Dim ctrl = _
From control In wcICausedPostBack.Parent.Controls.OfType(Of WebControl)() _
Where control.TabIndex > indx _
Select control
ctrl.DefaultIfEmpty(wcICausedPostBack).First().Focus()
End If
End Sub
Protected Function GetControlThatCausedPostBack(ByVal page As Page) As Control
Dim control As Control = Nothing
Dim ctrlname As String = page.Request.Params.Get("__EVENTTARGET")
If ctrlname IsNot Nothing AndAlso ctrlname <> String.Empty Then
control = page.FindControl(ctrlname)
Else
For Each ctl As String In page.Request.Form
Dim c As Control = page.FindControl(ctl)
If TypeOf c Is System.Web.UI.WebControls.Button OrElse TypeOf c Is System.Web.UI.WebControls.ImageButton Then
control = c
Exit For
End If
Next ctl
End If
Return control
End Function
The code makes use of the GetControlThatCausedPostBack function written by Ryan to find the control that caused the postback. We then determine the TabIndex of the control and use LINQ to select the control with the next tabindex and set focus to it .I have used LINQ as I find it very useful when I loop over collections. It gives me all the control I need over the code, keeping it tight and without much effort.
Just run the application and test out the functionality. When you tab out of a TextBox or click on the Button control, the focus shifts to the next control after a postback. That’s it for now. I hope you liked the article and I thank you for viewing it.