从渲染的控件ID中移除ctl00$ContentBody$

7
我对一个之前只是纯HTML和Javascript的应用程序进行了一些更改。为了添加服务器端功能,我选择了ASP.NET,并利用了主页面概念。不幸的是,在一个巨大的Web表单上,控件ID都被“ctl00$ContentBody$”前缀弄乱了。我在所有INPUT控件上添加了runat="server",这就改变了ID。现在ID已经改变,而JavaScript(写得非常糟糕,我甚至无法阅读,而我对JS非常有经验)完全失效了。
那么,我该如何防止这种荒谬的事情被渲染到HTML中呢?我希望能够创建一个继承HtmlGenericControl的类(我没有使用Web控件,我只是在每个input标签上添加了runat="server"),并覆盖将此“容器ID”放在ID和NAME属性开头的逻辑。然后,我可以在web.config中使用tagMapping进行全局更改。这可行吗?

我找不到任何支持我的链接,但我相信下一个版本的.NET将会给你删除它的能力。在那之前,你需要一个解决方法。你可以使用普通控件并添加文字来设置值,例如:<input type='hidden' name='blah' value='<asp:literal runat="server" id="blahValue" />' />。 - mjallday
9个回答

6

暂时的安慰是,这个“特性”将在Asp.Net 4.0中得到修复。您将获得可设置的ClientID属性。

除此之外,其他回答都很好。
使用<%= control.ClientID %>

或者添加JQuery并使用$("[id$='myId'])

或者,在您的输入标签上,不要添加runtime='server'。您应该能够通过Form成员检索值(就像传统的asp一样)

或者,跳过Asp.Net WebForms并直接使用Asp.Net MVC,它可以完全控制生成的HTML标记。您需要更改做事情的方式,但这可能会让您感到 less frustrating。


<system.web> <pages clientIDMode="Static"></pages> </system.web>https://dev59.com/VlXTa4cB1Zd3GeqP4b7z - Khalid Bin Sarower

4
我尝试了这段代码,但它不知何故重新排列了整个页面:
Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
    Dim Html As New StringWriter()
    Dim Render As New HtmlTextWriter(Html)
    MyBase.Render(Render)
    writer.Write(Html.ToString().Replace("name=""ctl00$ContentBody$", "name=""").Replace("id=""ctl00_ContentBody_", "id="""))
End Sub

如果您想查看我提交的示例,请访问URL链接。

2

我不知道有什么办法可以从控件ID中移除命名容器。过去我使用了一个便利的方法,在javascript中查找这些id,它会遍历标记名称并使用正则表达式匹配那个以$realID结尾的标记名称,其中realID是我在标记中给控件的id。现在,我会使用jQuery来完成这个操作,使用类似下面的选择器:

 $('[id$="realID"]')

这基本上与我的旧便捷方法做的一样,但它已经内置到框架中了。


我不会更改或编写任何客户端脚本。当前的脚本是难以阅读的,我的“客户”(哈)没有支付我重写它的费用。我在问题中已经明确表明了这一点。 - Josh Stodola

0
实际上,为了借鉴Josh的答案,我发现下面的第一个解决方案在处理其他输入控件元素和PostBacks时存在问题。因此,我选择了下面的第二个解决方案来更改JavaScript而不是元素名称。

Josh的解决方案:

代码后台:

protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
    StringWriter Html = new StringWriter();
    HtmlTextWriter Render = new HtmlTextWriter(Html);
    base.Render(Render);
    writer.Write(Html.ToString()
        .Replace("name=\"ctl00$ContentBody$", "name=\"")
        .Replace("id=\"ctl00_ContentBody_", "id=\""));
}
解决方案1,存在PostBack问题(注意:我无法更改ID以解决此问题):

代码后台:

protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
    var html = new StringWriter();
    var render = new HtmlTextWriter(html);
    base.Render(render);
    writer.Write(html.ToString()
        .Replace("name=\"ctl00$contentBody$rbl",
                 "name=\"ctl00_contentBody_rbl"));
}

解决方案 2,改变 JavaScript:

在使用约定“rbl[name]”的单选按钮列表的 aspx 文件中的 JavaScript:

if (!validateRadioButtonList("<% =rblTitle.ClientID %>"))

代码后台:

protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
    var html = new StringWriter();
    var render = new HtmlTextWriter(html);
    base.Render(render);
    writer.Write(html.ToString()
        .Replace("validateRadioButtonList(\"ctl00_contentBody_rbl", 
                 "validateRadioButtonList(\"ctl00$contentBody$rbl"));
}

0

我想在这个问题上加入我的两分钱:

我是按照被接受的答案所述的方法来做的,但我认为覆盖 Render 控件以写入新的 TextWriter,然后将其内容写入页面的 OutputStream 似乎浪费资源。我发现可以通过创建一个小类来覆盖 HtmlTextWriter 类来完成此操作。这样我们就可以直接写入流,只有在用作属性时才尝试替换文本。

public class CleanHtmlTextWriter : HtmlTextWriter
{
    private const string MASTER_PAGE_ID = "ctl00";
    private const string CONTENT_NAME = "MainContent";

    public CleanHtmlTextWriter(TextWriter writer)
        : base(writer)
    {
    }

    public override void WriteAttribute(string name, string value)
    {
        if (name == "name")
            value = value.Replace(CONTENT_NAME + "$", "").Replace(MASTER_PAGE_ID + "$", "");

        if (name == "id")
            value = value.Replace(CONTENT_NAME + "_", "").Replace(MASTER_PAGE_ID + "_", "");

        base.WriteAttribute(name, value);
    }
}

然后你可以像这样使用它:
protected override void Render(HtmlTextWriter writer)
{
    base.Render(new CleanHtmlTextWriter(writer));
}

0
据我所知,没有办法删除它们,正如你所说的那样;以确保它们是唯一的。在我看来,你有两个选择:
  1. 创建一个JS变量,并将其添加到所有JS调用之前,以便查找正确的ID
  2. 在你的javascript中使用<%= control.ClientID %>,这样它就会使用新的ID。
如果你的任何输入都在其他服务器标记内部,那么选项1就不起作用。这容易出现许多问题,因此如果可以的话,我会选择选项2。
选项2取决于javascript本身是否在页面上,或者如果JS是外部的,则需要能够传递ID。这段代码没有经过测试,仅供参考,但这就是我的意思:
function alertValue(textID){
     alert(document.GetElementById(textID).value);
}

<input id="txtBox" runat="server" type="Button" text="Click Me" onClick="alertValue('<%= txtBox.ClientID %>');" />

这真的取决于您的JS是如何实现的。


0

看起来您只是想从最终输出中删除客户端ID,因此您可能可以在页面上覆盖“render”事件并使用正则表达式将它们删除。您可以在下面的帖子中看到示例。

重写ASP.NET页输出

在获得要处理的文本后,您很可能可以编写类似于以下内容的东西...

output = Regex.Replace(
    output, 
    @"id\=""ctl00\$[^\""]*""", 
    string.Empty, 
    RegexOptions.IgnoreCase
    );

然后将最终输出写入HtmlTextWriter。

希望这有所帮助。


0

0

我需要的是快速而简单的解决方案,感谢HBoss,我成功地找到了一个非常简单的解决方案。在相关页面的代码后台中,我只需添加这个子程序...

Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
    Dim Html As New StringWriter()
    Dim Render As New HtmlTextWriter(Html)
    MyBase.Render(Render)
    writer.Write(Html.ToString().Replace("name=""ctl00$ContentBody$", "name=""").Replace("id=""ctl00_ContentBody_", "id="""))
End Sub

1
如果您没有使用服务器端功能,为什么要添加runat=server标签呢?如果您这样做了,就会破坏框架将控件正确映射回服务器端的能力。不要尝试在任何具有postback的控件中使用网格或重复器。当然,您必须更改脚本,因为它们不会是ctl00 - 它们每个都会有一个唯一的编号。 - tvanfosson
我需要使用runat="server"来通过代码后台设置值。控件正确映射回服务器端,因为我没有启用EventValidation,并且通过Request.Form集合检索值。谢谢。 - Josh Stodola

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接