Brian
Brian

Reputation: 1184

Set Focus to Any Control After PostBack

First I have 3 TextBoxes, a DropDownList, a CheckBox, and 2 LinkButtons in a table. The TextBoxes and DropDownList must do an AutoPostBack because there are some calculations being done on the server side which called by OnTextChanged.

My issue here is that after the content of any Control (which requires a PostBack) changes and you attempt to move focus to any other Control on the page (whether it be tabbing or using the mouse to click on any other Control) the focus does not move to the next Control or the Control you clicked.

I tried using a method which finds the current Control and based on the TabIndex, adds 1 which moves the focus to the next control. The problem here is that it does not allow for focus to be set on any other Control other than that one with the next TabIndex. To better explain here is an example of the situation.

Example: I have TextBox1, TextBox2, and TextBox3. I change the content in TextBox2 then want to move backwards to TextBox1. When I click in TextBox1 the focus is set to TextBox3 since the code is using the order of the TabIndex. ** A key factor here is that TextBox1 DOES get focus before the server side code fires but then loses focus and sets it on TextBox3 **

To me, it seems like the only way this can be accomplished would be to add a function on the client side which finds the Control with focus before the PostBack occurs, then reset the focus on that Control after the server side code completes. It does not seem like anything I do on the server side will work since the focus has already been lost when this occurs.

I have searched and searched but have not been able to find any solution to this particular issue, everything I have found deals with setting focus to the NEXT Control instead of the Control you want to have focus. Any help would be greatly appreciated. Thank you in advance.

Here is the code I am using to move to the next Control based on the TabIndex but this does not work in my situation.

protected void Page_Load(object sender, EventArgs e)
    {
        WebControl ctrl = GetPostBackControl() as WebControl;
        if (ctrl != null && !SetNextFocus(Controls, ctrl.TabIndex + 1)) { ctrl.Focus(); }
    }

public Control GetPostBackControl()
    {
        Control control = null;

        string ctrlname = Request.Params.Get("__EVENTTARGET");
        if (ctrlname != null && ctrlname != string.Empty)
        {
            control = FindControl(ctrlname);
            control.Focus();
        }
        else
        {
            foreach (string ctl in Request.Form)
            {
                Control c = FindControl(ctl);
                if (c is Button)
                {
                    control = c;
                    break;
                }
            }
        }
        return control;
    }

    private bool SetNextFocus(ControlCollection controls, int tabIndex)
    {
        foreach (Control control in controls)
        {
            if (control.HasControls())
            {
                bool found = SetNextFocus(control.Controls, tabIndex);
                if (found) { return true; }
            }

            WebControl webControl = control as WebControl;
            if (webControl == null) { continue; }
            if (webControl.TabIndex != tabIndex) { continue; }

            webControl.Focus();
            return true;
        }

        return false;
    }

Upvotes: 4

Views: 15165

Answers (2)

Brian
Brian

Reputation: 1184

Thank you for the help, it did get me a little closer. The only thing that was preventing it from working correctly is that my page has some variables which are being carried over from other pages. When the page loads, the override is causing the page to break since it is unable to locate those controls. I was able to fix the issue by adding a HiddenField on the .aspx page and adding the following code to the onload() function:

if (document.getElementById("HiddenField1").value != "") { 
    var contr = document.getElementById(document.getElementById"HiddenField1").value);
    contr.focus();
    document.getElementById("HiddenField1").value = "";
} 

as well as adding a new function which is called on each of the TextBoxes:

function tabFocus(e) {
    document.getElementById("HiddenField1").value = e.id;
}

I ended up not having to make any changes in the code behind. Once again, thank you for the help!

Upvotes: 0

James Johnson
James Johnson

Reputation: 46047

Try doing something like this to retain focus after postback:

/// <summary>
/// Overrides the OnLoad event moves the cursor to the appropriate control.
/// </summary>
/// <param name="e"></param>
protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    int currentTabIndex = 1;
    WebControl postBackCtrl = (WebControl)GetControlThatCausedPostBack(Page);    

    foreach (WebControl ctrl in Panel1.Controls.OfType<WebControl>())
    {
        ctrl.TabIndex = (short)currentTabIndex;
        if (postBackCtrl != null)
        {
            if (ctrl.TabIndex == postBackCtrl.TabIndex + 1)
                ctrl.Focus();
        }
        currentTabIndex++;
    }                                        
}


/// <summary>
/// Retrieves the control that caused the postback.
/// </summary>
/// <param name="page"></param>
/// <returns></returns>
private Control GetControlThatCausedPostBack(Page page)
{
    //initialize a control and set it to null
    Control ctrl = null;

    //get the event target name and find the control
    string ctrlName = Page.Request.Params.Get("__EVENTTARGET");
    if (!String.IsNullOrEmpty(ctrlName))
        ctrl = page.FindControl(ctrlName);

    //return the control to the calling method
    return ctrl;
}

Upvotes: 4

Related Questions