使用 AssociateControlID 呈现动态标签 WebControl 时抛出异常

Exception thrown when rendering a dynamic label WebControl with the AssociateControlID

我在调用 Web 服务时遇到异常,该服务在 运行 时动态构建 HTML 元素并且 returns 将呈现的元素作为字符串。

调用 RenderControl() 方法时出现以下错误:

System.Web.HttpException: 无法找到与标签 'lblCertificate'.

相关联的 ID 为 'txtCertificate' 的控件
StringWriter stringWriter = new StringWriter();
HtmlTextWriter writer = new HtmlTextWriter(stringWriter);

// Create System.Web.UI.WebControls.Panel (container)
Panel pnlFRow1 = new Panel();
pnlFRow1.CssClass = "f-row";

// Create System.Web.UI.WebControls.Textbox
TextBox txtCertificate = new TextBox();
txtCertificate.ID = "txtCertificate";
txtCertificate.CssClass = "f-input f-input-full";

// Create System.Web.UI.WebControls.Label
Label lblCertificate = new Label();
lblCertificate.ID = "lblCertificate";
lblCertificate.CssClass = "f-label f-label-full";
lblCertificate.AssociatedControlID = txtCertificate.ID;
lblCertificate.Text = "Certificate:";
Panel pnlCertificate = new Panel();
pnlCertificate.CssClass = "f-label f-label-full";

// Binding child controls to parent controls
pnlFRow1.Controls.Add(lblCertificate);
pnlFRow1.Controls.Add(pnlCertificate);
pnlCertificate.Controls.Add(txtCertificate);

// Render control
pnlContent.RenderControl(writer);

// Return rendered HTML
return writer.InnerWriter.ToString();

我尝试将行 pnlFRow1.Controls.Add(lblCertificate); 放在行 pnlCertificate.Controls.Add(txtCertificate); 之后,认为这可能是顺序重要的问题,但是这会导致同样的错误。

为了使 Label WebControl 呈现为实际的 <label> 元素,AssociatedControlID 属性是必须具备的,并且必须在输入控件之前显示。

一种方法是继承 Label class,并用您更喜欢的东西替换 RenderBeginTag 方法。如果你嵌套标签 class 它应该保留在本地上下文中并阻止它泄漏到你的应用程序的其余部分

例如:

public partial class _Default : Page 
{
        public class Label : System.Web.UI.WebControls.Label {
        public string For = null;
        public override void RenderBeginTag(HtmlTextWriter writer) {
            AddAttributeIfExists(writer, "ID", ID);
            AddAttributeIfExists(writer, "For", For);
            writer.RenderBeginTag("Label");
        }
        private void AddAttributeIfExists(HtmlTextWriter writer, string name, string value) {
            if (!string.IsNullOrWhiteSpace(value))
                writer.AddAttribute(name, value);
        }
    }

    protected void Page_Load(object sender, EventArgs e) {
        StringWriter stringWriter = new StringWriter();
        HtmlTextWriter writer = new HtmlTextWriter(stringWriter);

        Panel test = new Panel() { ID = "PanelTest" };

        TextBox txtCertificate = new TextBox() { ID = "txtCertificate" };
        Label lblCertificate = new Label() { ID = "lblCertificate", Text = "Certificate", For = txtCertificate.ClientID };

        test.Controls.Add(lblCertificate);
        test.Controls.Add(txtCertificate);

        test.RenderControl(writer);
        string teststring = writer.InnerWriter.ToString();
    }
}

注意: 您现在可以使用自定义的 For 属性 而不是使用 AssociatedControlId,它会做同样的事情。还要注意标签 class 是如何嵌套在您的页面 class 中的,因此它不会干扰其他页面。

不幸的是,正如我们在此答案的第一个版本中发现的那样,如果您尝试在没有 AssociatedControlId 的情况下使用 .Attributes["for"],.NET 会将 <Label> 转换为 <span>,所以上面的例子应该解决这个问题。