为什么用 'runat="server"' 装饰 HTML 元素不能使它们可以从代码隐藏访问?

Why does decorating HTML elements with 'runat="server"' not make them accessible from the code-behind?

根据这个 How to access html controls in code behind,我应该可以像这样将 'runat="server"' 添加到我的 html 元素中:

<input type="email" id="email" runat="server" />

...然后通过 C# 中的 ID 访问 html 元素,如下所示:

String usersEmail = email.Value;

但是,尝试这样做会导致“名称 'email' 在当前上下文中不存在

试图访问 html 元素以从代码隐藏进行操作真的是失败的原因吗?

更新

根据 Steve Brookes 的建议 answer/response,这是我的 ascx 文件顶部的内容:

<%@ Control Language="C#" AutoEventWireup="true" 
CodeBehind="PostTravelWizardWebPartUserControl.ascx.cs"
Inherits="PostTravelWizard.PostTravelWizardWebPart.PostTravelWizardWebPartUserControl" %>

...而布鲁克斯先生推荐这样的东西:

<%@Page Language="C#" AutoEventWireup="false" CodeFile="Default.aspx.cs" 
Inherits="_Default"%>

这够近了吧? IOW,而不是 "Page" 我有 "Control" (它派生自 UserControl);我有 "CodeBehind" 而不是 "CodeFile" 并且我的继承不同。

我尝试将 AutoEventWireup 切换为 false,但没有任何区别。

更新 2

谢谢索林,

我不知道该要求(将所有内容都包含在 "form" 标记中),但即使这样做了:

<form id="formPostTravel" runat="server">
   . . .  (all the html elements)
</form>

...没有区别;我仍然明白,"The name 'email' does not exist in the current context"

更新 3

对 Steve Brookes 的建议的另一种回应是 "changing CodeBehind to CodeFile and adding an Inherits attribute which should match the class name of your code behind file. The other suggestion is changing the ID to EmailAddress or something as it might be some sort of naming conflict with a reserved word!":

首先,我将 CodeBehind 更改为 CodeFile

然后,我验证了 Inherits 属性与我的代码隐藏文件的 class 名称相匹配。该文件是:

namespace PostTravelWizard.PostTravelWizardWebPart
{
    public partial class PostTravelWizardWebPartUserControl : UserControl

...继承值为“PostTravelWizard.PostTravelWizardWebPart.PostTravelWizardWebPartUserControl

最后,我还把HTML元素的ID从'email'改成了'emailaddress':

<input type="email" id="emailaddress" runat="server" />

...但现在我得到,“名称 'emailaddress' 在当前上下文中不存在

更新 4

有关这里正在尝试的内容的一些背景信息。

这里是 "email" 输入定义的地方,在 *.ascx 文件中,在 html 块中:

<input type="email" id="emailaddress" runat="server" />

这是我试图从相应的 *.ascx.cs 文件中访问它的值的方式:

namespace PostTravelWizard.PostTravelWizardWebPart
{
    public partial class PostTravelWizardWebPartUserControl : UserControl
    {
    . . .
    String usersEmail = emailaddress.Value; 

但我得到的回报是,“名称 'emailaddress' 在当前上下文中不存在

更新 5

遵循 Steven Brookes 的建议:

您可以右键单击ascx文件并查看设计器,然后更改为查看代码。这可能会重新生成设计器文件

我能够将 一些 字段放入 designer.cs;其他(大多数)是因为他们开始 "hidden"?我不知道...

您可能忘记将其放入服务器端表单中:

  <form id="form1" runat="server">
    <input type="email" id="email" runat="server" />
  </form>
在你能够从您的代码隐藏访问它们。

更新 1

我创建了一个测试网络表单和测试用户控件,并将用户控件放在网络表单中。这是所有代码:

TestWebForm.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestWebForm.aspx.cs" Inherits="TestWeb.TestWebForm" %>
<%@ Register TagPrefix="uc" src="~/TestWebUserControl.ascx" tagName="TestWebUserControl" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
    <form id="form1" runat="server">
        <uc:TestWebUserControl id="TestWebUser" runat="server" />
    </form>
</body>
</html>

TestWebForm.aspx.cs

using System;
using System.Web.UI;

namespace TestWeb
{
    public partial class TestWebForm : Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            var y = TestWebUser.InnerControlEmail.Value;
        }
    }
}

TestWebUserControl.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="TestWebUserControl.ascx.cs" Inherits="TestWeb.TestWebUserControl" %>

<input type="email" id="ControlEmail" runat="server" />

TestWebUserControl.ascx.cs

using System;
using System.Web.UI;
using System.Web.UI.HtmlControls;

namespace TestWeb
{
    public partial class TestWebUserControl : UserControl
    {
        public HtmlInputGenericControl InnerControlEmail
        {
            get { return ControlEmail; }
        }
        protected void Page_Load(object sender, EventArgs e)
        {
            var x = ControlEmail.Value;
        }
    }
}

这对我有用。请注意,我必须更改 <%@ Register %> 标记以使用 srctagName 属性而不是默认的 NamespaceAssembly 属性。

此外,html 控件最终包含在 Web 表单中的 <form> 标记中,因此在用户控件中不需要它。

感谢 属性,html 控件可以通过放置此用户控件的表单访问。

更新 2

这是 TestWebUserControl.ascx.designer.cs 文件:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated. 
// </auto-generated>
//------------------------------------------------------------------------------

namespace TestWeb {


    public partial class TestWebUserControl {

        /// <summary>
        /// ControlEmail control.
        /// </summary>
        /// <remarks>
        /// Auto-generated field.
        /// To modify move field declaration from designer file to code-behind file.
        /// </remarks>
        protected global::System.Web.UI.HtmlControls.HtmlInputGenericControl ControlEmail;
    }
}

如果我删除 protected global::System.Web.UI.HtmlControls.HtmlInputGenericControl ControlEmail;,我就会得到你的确切错误。所以你的设计器文件很可能出了问题。

从您的 .ascx 文件中删除 html 控件定义 (<html id="email"/>),尝试编译(您会遇到错误),重新添加它,尝试编译(您会遇到错误) 再次尝试编译(现在应该可以了)。

您的页面是 asp.net 页面吗?如果是这样,请确保您的页面指令正确指向您的代码隐藏文件。像这样的东西应该在你的页面顶部:

<%@Page Language="C#" AutoEventWireup="false" CodeFile="Default.aspx.cs" Inherits="_Default"%>

有时 Visual Studio 忘记在“.designer”文件中定义您的服务器端控件,您无法从隐藏代码访问它们

在这些情况下,您必须在代码中手动定义这些元素。

请注意,您必须使用元素的确切类型和名称以及 'protected' 成员

来定义这些变量