J'ai créé un petit script pour préserver l'élément ciblé lors d'une publication asynchrone, et cela fonctionne parfaitement bien sauf lorsque vous parcourez les contrôles générés dans un asp: Repeater, où une publication complète est déclenché pour une raison mystérieuse. Voici un exemple concis avec lequel travailler:

<%@ Page Language="C#" EnableEventValidation="false" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <title></title>
    <script runat="server">
        public IEnumerable<int> Measurements_GetData()
        {
            return new[] { 123, 328, 1099 };
        }
    </script>
</head>
<body>
    <form method="post" runat="server">
        <asp:ScriptManager runat="server" />
        <asp:UpdatePanel runat="server">
            <ContentTemplate>
                <h1>OK</h1>
                <div>
                    <asp:TextBox ID="Measurement1" runat="server" Text="123" AutoPostBack="true"  />
                </div>

                <div>
                    <asp:TextBox ID="TextBox1" runat="server" Text="328" AutoPostBack="true" />
                </div>

                <div>
                    <asp:TextBox ID="TextBox2" runat="server" Text="1099" AutoPostBack="true" />
                </div>

                <h1>Not OK</h1>
                <asp:Repeater ID="Measurements" runat="server" SelectMethod="Measurements_GetData" ItemType="System.Int32">
                    <ItemTemplate>
                    <div>
                        <asp:TextBox ID="Measurement" runat="server" AutoPostBack="true" Text="<%# Item %>" />
                    </div>
                    </ItemTemplate>
                </asp:Repeater>
            </ContentTemplate>
        </asp:UpdatePanel>
    </form>
    <script type="text/javascript">
        (function () {
            var focusedElementId = "";
            var prm = Sys.WebForms.PageRequestManager.getInstance();

            prm.add_pageLoaded(function (source, args) {
                // re-focus element, if any selected prior to postback
                if (focusedElementId !== "") {
                    document.getElementById(focusedElementId).focus();
                    console.log("focus:" + focusedElementId);
                }
            });

            prm.add_pageLoading(function (source, args) {
                var fe = document.activeElement;
                focusedElementId = fe !== null ? fe.id : "";
            });
        })();
    </script>
</body>
</html>

Cet exemple montre à la fois le comportement de travail et le comportement non fonctionnel. Si vous cliquez sur la première zone de texte, changez la valeur, tabulation au suivant, changez la valeur, tabulation au suivant, il conserve correctement le focus sur le dernier élément et vous pouvez voir la progression des éléments focalisés conservés dans la console JS.

Maintenant, si vous regardez la console JS et cliquez sur la première entrée de texte dans le balisage généré par le répéteur (section Pas OK), changez puis tabulation, changez puis tabulez à nouveau, vous pouvez voir que le focus est perdu sur le dernier contrôle car une publication complète est déclenchée (La console JS est effacée).

Qu'est-ce qui se passe ici? Cela ressemble à un bogue de formulaires Web, je ne peux pas y donner un sens autrement. S'il s'agit d'un bogue, existe-t-il une solution de contournement?

1
naasking 17 janv. 2017 à 18:13

2 réponses

Meilleure réponse

Comme je le soupçonnais, il s'agit d'un problème connu dans les formulaires Web ASP.NET. Cela est dû aux modifications ClientIDMode dans ASP.NET 4.0. MS a publié quelques solutions de contournement ici.

Si vous ne vous souciez pas des ID générés des contrôles, la solution la plus simple semble être retour au comportement pré-ASP.NET 4.0 en définissant:

<pages ClientIDMode="AutoID" / 

Dans web.config.

1
naasking 26 janv. 2017 à 15:07

Cela ne ressemble pas à un bogue, mais votre fonction JavaScript est en quelque sorte la cause du PostBack. Si vous le supprimez complètement, les TextBoxes se comportent comme ils le devraient. Il y a probablement une incompatibilité entre les TextBoxes liées par votre script (qui ne sont déclenchées que lorsque la page est chargée pour la première fois) et celles qui sont regénérées à l'intérieur du Repeater après une publication asynchrone.

Si vous enregistrez toutes les TextBoxes pour Async PostBack, elles fonctionneront à nouveau.

protected void Page_Load(object sender, EventArgs e)
{
    foreach (RepeaterItem item in Measurements.Items)
    {
        TextBox tb = item.FindControl("Measurement") as TextBox;
        ScriptManager.GetCurrent(Page).RegisterAsyncPostBackControl(tb);
    }
}
0
VDWWD 17 janv. 2017 à 17:06