UpdatePanel с типом ввода, отличным от текста в html5 - PullRequest
10 голосов
/ 28 декабря 2011

Я занимаюсь разработкой проекта с открытым исходным кодом для рендеринга HTML5 с использованием ASP.NET. Здесь вы можете посмотреть: http://asphtml5.codeplex.com/

теперь у меня проблема с панелью обновлений при отправке обратно входных значений, которые имеют тип, отличный от 'text'. Как вы, наверное, знаете, HTML 5 ввел несколько типов ввода, например, «число», «телефон», «поиск» и т. д. Теперь, если я отображаю такие элементы управления, все нормально работает в нормальных ситуациях, но если я помещу их внутри UpdatePanel, никакое значение не будет отправлено обратно, и значение будет сброшено.

Вот небольшой фрагмент кода, который выдает ту же ошибку:

    <asp:UpdatePanel runat="server" ID="UP">
        <ContentTemplate>
            <p>
                Enter A Number:
                <asp:TextBox runat="server" ID="Number2" type="number" />
            </p>
            <asp:Button Text="Submit" runat="server" ID="BtnSubmit" OnClick="BtnSubmit_Click" />
            <p>
                You entered :
                <asp:Label Text="" ID="LblValue" runat="server" />
            </p>
        </ContentTemplate>
    </asp:UpdatePanel>

если вы тестируете этот код в браузере, поддерживающем html 5, скажем, в качестве примера, например, в Chrome, будет показано поле Numeric Up-Down. но если вы нажмете кнопку отправки, она потеряет введенное вами значение.

вот код для обработчика событий:

        protected void BtnSubmit_Click(object sender, EventArgs e)
        {
            LblValue.Text = Number2.Text;
        }

я уже пробовал читать коды классов UpdatePanel, ScriptManager и ScriptManagerProxy, ничего не найдено.

Думаю, мне может понадобиться создать собственные классы UpdatePanel и / или ScriptManager для использования.

Может ли кто-нибудь мне помочь и сказать, где проверить.

Ответы [ 3 ]

2 голосов
/ 01 января 2012

Хорошо, тогда я нашел способ это исправить. Прежде всего я обнаружил проблему с кодом, который предоставил Тим Медора. Все это было ошибкой this. модификатора. Итак, этот JavaScript исправил проблему:

var _textTypes = /^(text|password|hidden|search|tel|url|email|number|range|color|datetime|date|month|week|time|datetime-local)$/i;
function Sys$WebForms$PageRequestManager$_onFormSubmit(evt) {
...
if (_textTypes.test(type) ||
       (((type === 'checkbox') || (type === 'radio')) && element.checked)) {
       formBody.append(encodeURIComponent(name));
       formBody.append('=');
       formBody.append(encodeURIComponent(element.value));
       formBody.append('&');
...
}

Теперь я должен был добавить свою функцию в ScriptResource.axd. На данный момент я нашел способ, который, кажется, работает:

Я создал класс ScriptResouceHandler, который расширяет System.Web.Handlers.ScriptResourceHandler в пространстве имен DotM.Html5.Handlers.

в его ProcessRequest я позвонил base.ProcessRequest(context), чтобы сделать свою работу. Но я хотел добавить свою функцию к той, которая отображает оригинальную функцию. Я узнал, что это было, когда был зашифрован ZSystem.Web.Extensions,4.0.0.0,,31bf3856ad364e35|MicrosoftAjaxWebForms.debug.js|.

Другая проблема заключалась в том, что в System.Web.Handlers.ScriptResourceHandler внутренний метод Page.DecryptString 'вызывается для расшифровки параметра строки запроса. поэтому я не мог вызвать этот метод с помощью отражения.

вот код:

        protected sealed override void ProcessRequest(HttpContext context)
        {
            base.ProcessRequest(context);
            if (CypherContainsAjax(context.Request.QueryString["d"]))
                context.Response.Write(OnFormSubmit);
        }

        private bool CypherContainsAjax(string cypher)
        {
            var text = DecryptString(cypher);
            if (text == null)
                return true; //Then Add it everywhere. What else could I do? :D
            return text.Contains("MicrosoftAjaxWebForms");
        }

        private string DecryptString(string cypher)
        {
            if (PageDecryptString == null)
                return null;
            return (string)PageDecryptString.Invoke(null, new object[] { cypher });
        }
        private static MethodInfo PageDecryptString;
        static ScriptResourceHandler()
        {
            PageDecryptString = typeof(Page).GetMethod("DecryptString", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
        }

Вы можете назвать это своего рода уродливым взломом ...

2 голосов
/ 30 декабря 2011

Интересно, что платформа ASP.NET 4.0 AJAX, похоже, знает о типах ввода HTML 5 (см. Код), однако, как указал @TimSchmelter, это подтверждается Microsoft как ошибка.Это может дать вам отправную точку для отладки поведения и / или переопределения поведения по умолчанию и поиска решения.

Это также может быть ошибка в коде обработки на стороне сервера для этих типов ввода, хотя я 'Я не уверен, почему они должны заботиться об асинхронной обратной передаче по сравнению с обычной обратной передачей.

this._textTypes = /^(text|password|hidden|search|tel|url|email|number|range|color|datetime|date|month|week|time|datetime-local)$/i;

function Sys$WebForms$PageRequestManager$_onFormSubmit(evt) {
        var i, l, continueSubmit = true,
            isCrossPost = this._isCrossPost;
        this._isCrossPost = false;
        if (this._onsubmit) {
            continueSubmit = this._onsubmit();
        }
        if (continueSubmit) {
            for (i = 0, l = this._onSubmitStatements.length; i < l; i++) {
                if (!this._onSubmitStatements[i]()) {
                    continueSubmit = false;
                    break;
                }
            }
        }
        if (!continueSubmit) {
            if (evt) {
                evt.preventDefault();
            }
            return;
        }
        var form = this._form;
        if (isCrossPost) {
            return;
        }
        if (this._activeDefaultButton && !this._activeDefaultButtonClicked) {
            this._onFormElementActive(this._activeDefaultButton, 0, 0);
        }
        if (!this._postBackSettings || !this._postBackSettings.async) {
            return;
        }
        var formBody = new Sys.StringBuilder(),
            count = form.elements.length,
            panelID = this._createPanelID(null, this._postBackSettings);
        formBody.append(panelID);
        for (i = 0; i < count; i++) {
            var element = form.elements[i];
            var name = element.name;
            if (typeof(name) === "undefined" || (name === null) || (name.length === 0) || (name === this._scriptManagerID)) {
                continue;
            }
            var tagName = element.tagName.toUpperCase();
            if (tagName === 'INPUT') {
                var type = element.type;
                if (this._textTypes.test(type)
                    || ((type === 'checkbox' || type === 'radio') && element.checked)) {
                    formBody.append(encodeURIComponent(name));
                    formBody.append('=');
                    formBody.append(encodeURIComponent(element.value));
                    formBody.append('&');
                }
            }
            else if (tagName === 'SELECT') {
                var optionCount = element.options.length;
                for (var j = 0; j < optionCount; j++) {
                    var option = element.options[j];
                    if (option.selected) {
                        formBody.append(encodeURIComponent(name));
                        formBody.append('=');
                        formBody.append(encodeURIComponent(option.value));
                        formBody.append('&');
                    }
                }
            }
            else if (tagName === 'TEXTAREA') {
                formBody.append(encodeURIComponent(name));
                formBody.append('=');
                formBody.append(encodeURIComponent(element.value));
                formBody.append('&');
            }
        }
        formBody.append("__ASYNCPOST=true&");
        if (this._additionalInput) {
            formBody.append(this._additionalInput);
            this._additionalInput = null;
        }

// truncated for length
1 голос
/ 23 марта 2012

Это уже было исправлено в .Net 4 Reliability Update 1 (есть также версия 2, но она не содержит первую): http://support.microsoft.com/kb/2533523

Но если вы используете AjaxControlToolkit, он использует собственный внутренний файл MicrosoftAjaxWebForms.js, который является более старой веткой, и до сих пор нет официального исправления для него - вы можете использовать мое решение здесь: http://ajaxcontroltoolkit.codeplex.com/workitem/27041

Итак, вы можете либо включить в свой проект исправленный ToolkitScriptManager (я знаю, что это не так просто), либо попытаться включить новую версию MicrosoftAjaxWebForms.js, поэкспериментировав со свойствами vanilla ScriptManager AjaxFrameworkMode = "Explicit", Scripts или CompositeScript.

Используйте свойство AjaxFrameworkMode, чтобы включить все файлы сценариев Microsoft Ajax, отключить все файлы сценариев Microsoft Ajax или явно включить отдельные файлы сценариев.

Коллекция Scripts не содержит основных сценариев Microsoft Ajax Library. Сценарии в основной библиотеке отображаются автоматически; их не нужно регистрировать с помощью элемента управления ScriptManager. Однако если вы хотите переопределить основной сценарий или любой сценарий управления и заменить другую версию сценария, вы можете добавить свою версию в коллекцию сценариев.

<asp:ScriptManager runat="server">
  <Scripts>
    <asp:ScriptReference Path="~/MicrosoftAjaxWebForms.js" />
  </Scripts>
</asp:ScriptManager>

Вы можете получить новую версию MicrosoftAjaxWebForms.js из System.Web.Extensions Assembly Resources (с .Net Reflector) на компьютерах с установленным обновлением надежности 1.

...