UpdatePanel 的输入类型不是 html5 中的文本

发布于 2024-12-22 20:39:11 字数 1280 浏览 2 评论 0 原文

我正在开发一个使用 ASP.NET 渲染 HTML5 的开源项目。在这里你可以看一下: http://asphtml5.codeplex.com/

现在我在更新面板发回类型为非'文本'。如您所知,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 为例)上测试此代码,将会显示一个数字向上-向下字段。但如果您单击提交按钮,它将丢失您输入的值。

这是事件处理程序的代码:

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

我已经尝试过阅读 UpdatePanel、ScriptManager 和 ScriptManagerProxy 类代码,但没有找到任何内容。

我想我可能需要创建自己的 UpdatePanel 和/或 ScriptManager 类以供使用。

谁能帮帮我,告诉我去哪里检查。

I am developing an open source project for rendering HTML5 using ASP.NET. Here you can take a look:
http://asphtml5.codeplex.com/

now I have a problem with update panel in posting back the input values that have type other than 'text'. as you might know, html 5 has introduced several input types, for example 'number', 'tel', 'search', etc. Now if I render such controls, everything works fine in normal situations, but if I put them inside an UpdatePanel, no value will be posted back and the value will be reset.

here is a small piece of code that produces the same error:

    <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>

if you test this code on a browser that supports html 5, lets say Chrome as an example, a Numeric Up-Down field will be shown. but if you click on the submit button, it will lose the value that you have entered.

here is the code for event handler:

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

what I have already tried is reading UpdatePanel, ScriptManager and ScriptManagerProxy classes codes, nothing found.

I think I might need to create my own UpdatePanel and/or ScriptManager classes for use.

Could anyone help me, and tell me where to check.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

烟酉 2024-12-29 20:39:11

有趣的是,ASP.NET 4.0 AJAX 框架似乎确实能够识别 HTML 5 输入类型(请参阅代码),但正如 @TimSchmelter 指出的那样,微软已确认这是一个错误。

这可能为您提供调试行为和/或覆盖默认行为并找到解决方案的起点。

这也可能是这些输入类型的服务器端处理代码上的错误,尽管我不确定为什么他们应该/会关心异步回发与正常回发。

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

Interestingly enough, the ASP.NET 4.0 AJAX framework does seem to be aware of HTML 5 input types (see code), yet as @TimSchmelter pointed out, this is confirmed by Microsoft as a bug.

This may give you a starting point for debugging the behavior and/or overriding the default behavior and finding a solution.

It could also be an error on the server-side processing code for these input types, although I'm not sure why they should/would care about an async postback versus a normal postback.

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
↙温凉少女 2024-12-29 20:39:11

好吧,我想出了一个办法来解决这个问题。
首先我发现Tim Medora提供的代码有问题。这都是 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 ,它扩展了命名空间 DotM.Html5.Handlers 中的 System.Web.Handlers.ScriptResourceHandler 。

在其 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);
        }

你可以称之为某种丑陋的黑客攻击......

All right then, I figured out a way to fix that.
First of all I found the problem with the code that Tim Medora provided. It all was the this. modifier's fault. So this JavaScript fixed the problem:

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('&');
...
}

Now I had to inject my function into ScriptResource.axd.
For now I found a way that seems to work:

I created a class ScriptResouceHandler that extends System.Web.Handlers.ScriptResourceHandler in namespace DotM.Html5.Handlers.

in its ProcessRequest I called base.ProcessRequest(context) to do its job. But I wanted to add my function to the one rendering original function. I found out that it was when the encrypted ZSystem.Web.Extensions,4.0.0.0,,31bf3856ad364e35|MicrosoftAjaxWebForms.debug.js| was passed.

Another problem was that in System.Web.Handlers.ScriptResourceHandler, 'Page.DecryptString' method which is internal is called to decrypt the query string param.
so there was no way for me to invoke that method via reflection.

here is the code:

        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);
        }

You may call this some kind of ugly hacking ...

说不完的你爱 2024-12-29 20:39:11

此问题已在 .Net 4 可靠性更新 1 中修复(还有版本 2,但不包含第一个版本): http://support.microsoft.com/kb/2533523

但是如果您使用的是 AjaxControlToolkit,它会使用自己的内部 MicrosoftAjaxWebForms.js这是一个较旧的分支,仍然没有官方修复 - 您可以从这里使用我的解决方案: http://ajaxcontroltoolkit.codeplex.com/workitem/27041

所以 - 你可以在你的项目中包含固定的 ToolkitScriptManager (我知道有点膨胀),或者你可以尝试通过尝试普通的 ScriptManager 属性 AjaxFrameworkMode="Explicit"、Scripts 或 CompositeScript 来包含新版本的 MicrosoftAjaxWebForms.js。

使用 AjaxFrameworkMode 属性启用所有 Microsoft Ajax 脚本文件、禁用所有 Microsoft Ajax 脚本文件或显式包含单个脚本文件。

脚本集合不包含核心 Microsoft Ajax 库脚本。核心库中的脚本自动渲染;它们不必向 ScriptManager 控件注册。但是,如果您想要覆盖核心脚本或任何控制脚本并替换该脚本的不同版本,则可以将您的版本添加到脚本集合中。

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

您可以在安装了 Reliability Update 1 的计算机上从 System.Web.Extensions 程序集资源(带有 .Net Reflector)获取新版本的 MicrosoftAjaxWebForms.js。

This was already fixed in .Net 4 Reliability Update 1 (there is also a version 2, but it does not contain the first one): http://support.microsoft.com/kb/2533523

But if you are using AjaxControlToolkit, it uses its own internal MicrosoftAjaxWebForms.js which is an older fork, and there is still no official fix for it - you can use mine solution from here: http://ajaxcontroltoolkit.codeplex.com/workitem/27041

So - you can either include the fixed ToolkitScriptManager with your project (a bloat, I know), or you can try to include the new version of MicrosoftAjaxWebForms.js by experimenting with vanilla ScriptManager properties AjaxFrameworkMode="Explicit", Scripts or CompositeScript.

Use the AjaxFrameworkMode property to enable all Microsoft Ajax script files, to disable all Microsoft Ajax script files, or to explicitly include individual script files.

The Scripts collection does not contain the core Microsoft Ajax Library scripts. The scripts in the core library are rendered automatically; they do not have to be registered with the ScriptManager control. However, if you want to override a core script or any control script and substitute a different version of the script, you can add your version to the Scripts collection.

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

You can get the new version of MicrosoftAjaxWebForms.js from System.Web.Extensions assembly Resources (with .Net Reflector) on machines with installed Reliability Update 1.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文