C# 如何在 ASP.NET 中使用按钮标记?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/187482/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 17:11:35  来源:igfitidea点击:

How can I use the button tag with ASP.NET?

c#asp.nethtmlhtmlbutton

提问by Adam Lassek

I'd like to use the newer <button>tag in an ASP.NET website which, among other things, allows CSS-styled text and embedding a graphic inside the button. The asp:Button control renders as <input type="button">, is there any way to make a preexisting control render to <button>?

我想<button>在 ASP.NET 网站中使用较新的标签,除其他外,它允许使用 CSS 样式的文本并在按钮内嵌入图形。asp:Button 控件呈现为<input type="button">,有什么方法可以使预先存在的控件呈现为<button>

From what I've read there is an incompatibility with IE posting the button's markup instead of the value attribute when the button is located within a <form>, but in ASP.NET it will be using the onclick event to fire __doPostBack anyway, so I don't think that this would be a problem.

从我读过的内容来看,当按钮位于<form>. t认为这将是一个问题。

Are there any reasons why I shouldn't use this? If not, how would you go about supporting it with asp:Button, or a new server control based on it? I would prefer to not write my own server control if that can be avoided.

有什么原因我不应该使用它吗?如果没有,您将如何使用 asp:Button 或基于它的新服务器控件来支持它?如果可以避免,我宁愿不编写自己的服务器控件。



At first the <button runat="server">solution worked, but I immediately ran into a situation where it needs to have a CommandName property, which the HtmlButton control doesn't have. It looks like I'm going to need to create a control inherited from Button after all.

起初该<button runat="server">解决方案有效,但我立即遇到了需要具有 HtmlButton 控件没有的 CommandName 属性的情况。看起来我将需要创建一个从 Button 继承的控件。

What do I need to do in order to override the render method and make it render what I want?

我需要做什么才能覆盖 render 方法并使其呈现我想要的内容?



UPDATE

更新

DanHerbert's reply has made me interested in finding a solution to this again, so I've spent some more time working on it.

DanHerbert 的回复让我有兴趣再次找到解决方案,所以我花了更多的时间来研究它。

First, there's a far easier way of overloading the TagName:

首先,有一种更简单的方法来重载 TagName:

public ModernButton() : base(HtmlTextWriterTag.Button)
{
}

The problem with Dan's solution as it stands is the innerhtml of the tag is placed into the value property, which causes a validation error on postback. A related problem is, even if you render the value property correctly, IE's braindead implementation of the <button>tag posts the innerhtml instead of the value anyway. So, any implementation of this needs to override the AddAttributesToRender method in order to correctly render the value property, and also provide some sort of workaround for IE so it doesn't completely screw up the postback.

Dan 的解决方案目前存在的问题是标签的 innerhtml 被放置在 value 属性中,这会导致回发验证错误。一个相关的问题是,即使您正确地呈现了 value 属性,IE 对<button>标签的脑残实现仍然会发布 innerhtml而不是值。因此,任何实现都需要覆盖 AddAttributesToRender 方法以正确呈现 value 属性,并为 IE 提供某种解决方法,因此它不会完全搞砸回发。

The IE problem may be insurmountable if you want to take advantage of the CommandName/CommandArgument properties for a databound control. Hopefully someone can suggest a workaround for this.

如果您想利用数据绑定控件的 CommandName/CommandArgument 属性,IE 问题可能是无法克服的。希望有人可以为此提出解决方法。

I have made progress on the rendering:

我在渲染方面取得了进展:

ModernButton.cs

ModernButton.cs

This renders as a proper html <button>with the correct value, but it doesn't work with the ASP.Net PostBack system. I've written some of what I need to provide the Commandevent, but it doesn't fire.

这将呈现为<button>具有正确值的正确 html ,但它不适用于 ASP.Net PostBack 系统。我已经写了一些我需要提供Command事件的内容,但它没有触发。

When inspecting this button side-by-side with a regular asp:Button, they look the same other than the differences I need. So I'm not sure how ASP.Net is wiring up the Commandevent in this case.

与常规 asp:Button 并排检查此按钮时,除了我需要的不同之外,它们看起来相同。所以我不确定Command在这种情况下ASP.Net 如何连接事件。

An additional problem is, nested server controls aren't rendered (as you can see with the ParseChildren(false) attribute). It's pretty easy to inject literal html text into the control during render, but how do you allow support for nested server controls?

另一个问题是,不会呈现嵌套的服务器控件(如您使用 ParseChildren(false) 属性所见)。在渲染期间将文字 html 文本注入控件非常容易,但是如何支持嵌套服务器控件?

采纳答案by Daniel Liuzzi

This is an old question, but for those of us unlucky enough still having to maintain ASP.NET Web Forms applications, I went through this myself while trying to include Bootstrap glyphs inside of built-in button controls.

这是一个老问题,但对于我们这些不幸仍然需要维护 ASP.NET Web 窗体应用程序的人来说,我在尝试将 Bootstrap 字形包含在内置按钮控件中时自己解决了这个问题。

As per Bootstrap documentation, the desired markup is as follows:

根据 Bootstrap 文档,所需的标记如下:

<button class="btn btn-default">
    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
    Search
</button>

I needed this markup to be rendered by a server control, so I set out to find options.

我需要由服务器控件呈现此标记,因此我开始寻找选项。

Button

按钮

This would be the first logical step, but —as this question explains— Button renders an <input>element instead of <button>, so adding inner HTML is not possible.

这将是第一个合乎逻辑的步骤,但是——正如这个问题所解释的—— Button 呈现一个<input>元素而不是<button>,因此添加内部 HTML 是不可能的。

LinkButton (credit to Tsvetomir Tsonev's answer)

LinkBut​​ton(归功于Tsvetomir Tsonev 的回答

Source

来源

<asp:LinkButton runat="server" ID="uxSearch" CssClass="btn btn-default">
    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
    Search
</asp:LinkButton>

Output

输出

<a id="uxSearch" class="btn btn-default" href="javascript:__doPostBack(&#39;uxSearch&#39;,&#39;&#39;)">
    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
    Search
</a>

Pros

优点

  • Looks OK
  • Commandevent; CommandNameand CommandArgumentproperties
  • 看起来不错
  • Command事件; CommandNameCommandArgument属性

Cons

缺点

  • Renders <a>instead of <button>
  • Renders and relies on obtrusive JavaScript
  • 渲染<a>而不是<button>
  • 渲染并依赖于引人注目的 JavaScript

HtmlButton (credit to Philippe's answer)

HtmlButton(归功于菲利普的回答

Source

来源

<button runat="server" id="uxSearch" class="btn btn-default">
    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
    Search
</button>

Result

结果

<button onclick="__doPostBack('uxSearch','')" id="uxSearch" class="btn btn-default">
    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
    Search
</button>

Pros

优点

  • Looks OK
  • Renders proper <button>element
  • 看起来不错
  • 渲染适当的<button>元素

Cons

缺点

  • No Commandevent; no CommandNameor CommandArgumentproperties
  • Renders and relies on obtrusive JavaScript to handle its ServerClickevent
  • Command事件;没有CommandNameCommandArgument属性
  • 渲染并依赖于引人注目的 JavaScript 来处理其ServerClick事件


At this point it is clear that none of the built-in controls seem suitable, so the next logical step is try and modify them to achieve the desired functionality.

在这一点上,很明显内置控件似乎都不合适,因此下一个合乎逻辑的步骤是尝试修改它们以实现所需的功能。

Custom control (credit to Dan Herbert's answer)

自定义控件(归功于Dan Herbert 的回答

NOTE: This is based on Dan's code, so all credit goes to him.

注意:这是基于 Dan 的代码,所以所有功劳都归功于他。

using System.Web.UI;
using System.Web.UI.WebControls;

namespace ModernControls
{
    [ParseChildren]
    public class ModernButton : Button
    {
        public new string Text
        {
            get { return (string)ViewState["NewText"] ?? ""; }
            set { ViewState["NewText"] = value; }
        }

        public string Value
        {
            get { return base.Text; }
            set { base.Text = value; }
        }

        protected override HtmlTextWriterTag TagKey
        {
            get { return HtmlTextWriterTag.Button; }
        }

        protected override void AddParsedSubObject(object obj)
        {
            var literal = obj as LiteralControl;
            if (literal == null) return;
            Text = literal.Text;
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.Write(Text);
        }
    }
}

I have stripped the class down to the bare minimum, and refactored it to achieve the same functionality with as little code as possible. I also added a couple of improvements. Namely:

我已将类精简到最低限度,并对其进行重构,以使用尽可能少的代码实现相同的功能。我还添加了一些改进。即:

  • Remove PersistChildrenattribute (seems unnecessary)
  • Remove TagNameoverride (seems unnecessary)
  • Remove HTML decoding from Text(base class already handles this)
  • Leave OnPreRenderintact; override AddParsedSubObjectinstead (simpler)
  • Simplify RenderContentsoverride
  • Add a Valueproperty (see below)
  • Add a namespace (to include a sample of @ Registerdirective)
  • Add necessary usingdirectives
  • 删除PersistChildren属性(似乎没有必要)
  • 删除TagName覆盖(似乎没有必要)
  • 删除 HTML 解码Text(基类已经处理了这个)
  • 保持OnPreRender原样;替代覆盖AddParsedSubObject(更简单)
  • 简化RenderContents覆盖
  • 添加Value属性(见下文)
  • 添加命名空间(以包含@Register指令的示例)
  • 添加必要的using指令

The Valueproperty simply accesses the old Textproperty. This is because the native Button control renders a valueattribute anyway (with Textas its value). Since valueis a valid attribute of the <button>element, I decided to include a property for it.

Value属性只是访问旧Text属性。这是因为本机 Button 控件value无论如何都会呈现一个属性(Text作为其值)。由于value<button>元素的有效属性,我决定为它包含一个属性。

Source

来源

<%@ Register TagPrefix="mc" Namespace="ModernControls" %>

<mc:ModernButton runat="server" ID="uxSearch" Value="Foo" CssClass="btn btn-default" >
    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
    Search
</mc:ModernButton>

Output

输出

<button type="submit" name="uxSearch" value="Foo" id="uxSearch" class="btn btn-default">
    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
    Search
</button>

Pros

优点

  • Looks OK
  • Renders a proper <button>element
  • Commandevent; CommandNameand CommandArgumentproperties
  • Does not render or rely on obtrusive JavaScript
  • 看起来不错
  • 渲染一个合适的<button>元素
  • Command事件; CommandNameCommandArgument属性
  • 不呈现或依赖于突兀的 JavaScript

Cons

缺点

  • None (other than not being a built-in control)
  • 无(除了不是内置控件)

回答by Tsvetomir Tsonev

I would go with a LinkButton and style it with CSS as appropriate.

我会使用 LinkBut​​ton 并根据需要使用 CSS 设置样式。

回答by Steven Robbins

You could make a new control, inheriting from Button, and override the render method, or use a .browser file to override all Buttons in the site, similar to the way the CSS Friendly stuff works for the TreeView control etc.

您可以创建一个新控件,从 Button 继承,并覆盖渲染方法,或使用 .browser 文件覆盖站点中的所有按钮,类似于 CSS 友好的东西适用于 TreeView 控件等的方式。

回答by Wayne

You can use the Button.UseSubmitBehaviorproperty as discussed in this article about rendering an ASP.NET Button control as a button.

您可以使用Button.UseSubmitBehavior属性,如这篇关于将 ASP.NET Button 控件呈现为按钮的文章中所述



编辑:对不起..这就是我在午休时略读问题的结果。是否有理由不使用 <button runat="server"> 标签或HtmlButtonhtml按钮

回答by Dan Herbert

I stumbled upon your question looking for the same exact thing. I ended up using Reflectorto figure out how the ASP.NET Buttoncontrol is actually rendered. It turns out to be really easy to change.

我偶然发现了你的问题,正在寻找同样的东西。我最终使用Reflector来弄清楚 ASP.NETButton控件是如何实际呈现的。事实证明,改变真的很容易。

It really just comes down to overriding the TagNameand TagKeyproperties of the Buttonclass. After you've done that, you just need to make sure you render the contents of the button manually since the original Buttonclass never had contents to render and the control will render a text-less button if you don't render the contents.

它实际上归结为覆盖类的TagNameTagKey属性Button。完成后,您只需要确保手动呈现按钮的内容,因为原始Button类从来没有要呈现的内容,如果不呈现内容,控件将呈现无文本按钮。

Update:

更新:

It's possible to make a few small modifications to the Button control through inheritance and still work fairly well. This solution eliminates the need to implement your own event handlers for OnCommand (although if you want to learn how to do that I can show you how that is handled). It also fixes the issue of submitting a value that has markup in it, except for IE probably. I'm still not sure how to fix IE's poor implementation of the Button tag though. That may just be a truly technical limitation that is impossible to work around...

可以通过继承对 Button 控件进行一些小的修改,并且仍然可以很好地工作。此解决方案消除了为 OnCommand 实现您自己的事件处理程序的需要(尽管如果您想学习如何做到这一点,我可以向您展示如何处理)。它还修复了提交包含标记的值的问题,IE 可能除外。我仍然不确定如何修复 IE 对 Button 标签的糟糕实现。这可能只是一个真正的技术限制,无法解决......

[ParseChildren(false)]
[PersistChildren(true)]
public class ModernButton : Button
{
    protected override string TagName
    {
        get { return "button"; }
    }

    protected override HtmlTextWriterTag TagKey
    {
        get { return HtmlTextWriterTag.Button; }
    }

    // Create a new implementation of the Text property which
    // will be ignored by the parent class, giving us the freedom
    // to use this property as we please.
    public new string Text
    {
        get { return ViewState["NewText"] as string; }
        set { ViewState["NewText"] = HttpUtility.HtmlDecode(value); }
    }

    protected override void OnPreRender(System.EventArgs e)
    {
        base.OnPreRender(e);
        // I wasn't sure what the best way to handle 'Text' would
        // be. Text is treated as another control which gets added
        // to the end of the button's control collection in this 
        //implementation
        LiteralControl lc = new LiteralControl(this.Text);
        Controls.Add(lc);

        // Add a value for base.Text for the parent class
        // If the following line is omitted, the 'value' 
        // attribute will be blank upon rendering
        base.Text = UniqueID;
    }

    protected override void RenderContents(HtmlTextWriter writer)
    {
        RenderChildren(writer);
    }
}

To use this control, you have a few options. One is to place controls directly into the ASP markup.

要使用此控件,您有几个选项。一种是将控件直接放入 ASP 标记中。

<uc:ModernButton runat="server" 
        ID="btnLogin" 
        OnClick="btnLogin_Click" 
        Text="Purplemonkeydishwasher">
    <img src="../someUrl/img.gif" alt="img" />
    <asp:Label ID="Label1" runat="server" Text="Login" />
</uc:ModernButton>

You can also add the controls to the control collection of the button in your code-behind.

您还可以将控件添加到代码隐藏中按钮的控件集合中。

// This code probably won't work too well "as is"
// since there is nothing being defined about these
// controls, but you get the idea.
btnLogin.Controls.Add(new Label());
btnLogin.Controls.Add(new Table());

I don't know how well a combination of both options works as I haven't tested that.

我不知道这两个选项的组合效果如何,因为我还没有测试过。

The only downside to this control right now is that I don't think it will remember your controls across PostBacks. I haven't tested this so it may already work, but I doubt it does. You'll need to add some ViewState management code for sub-controls to be handled across PostBacks I think, however this probably isn't an issue for you. Adding ViewState support shouldn't be terribly hard to do, although if needed that can easily be added.

目前此控件的唯一缺点是我认为它不会记住您跨回传的控件。我还没有测试过这个,所以它可能已经工作了,但我怀疑它确实有效。我认为您需要为要跨回发处理的子控件添加一些 ViewState 管理代码,但这对您来说可能不是问题。添加 ViewState 支持应该不难做到,尽管如果需要,可以轻松添加。

回答by David Andersson

I've been struggling all day with this -- my custom <button/>generated control not working:

我一整天都在为此苦苦挣扎 - 我的自定义<button/>生成的控件不起作用:

System.Web.HttpRequestValidationException: A potentially dangerous Request.Form value was detected from the client

System.Web.HttpRequestValidationException:从客户端检测到潜在危险的 Request.Form 值

What happens is that .Net adds a nameattribute:

发生的事情是 .Net 添加了一个name属性:

<button type="submit" name="ctl02" value="Content" class="btn ">
   <span>Content</span>
</button>

The nameattribute throws the server error when using IE 6 and IE 7. Everything works fine in other browsers (Opera, IE 8, Firefox, Safari).

name使用 IE 6 和 IE 7 时,该属性会引发服务器错误。在其他浏览器(Opera、IE 8、Firefox、Safari)中一切正常。

The cure is to hack away that nameattribute. Still I haven't figured that out.

治愈方法是破解该name属性。还是我没弄明白。

回答by Philippe

Although you say that using the [button runat="server"] is not a good enough solution it is important to mention it - a lot of .NET programmers are afraid of using the "native" HTML tags...

尽管您说使用 [button runat="server"] 不是一个足够好的解决方案,但重要的是要提及它 - 许多 .NET 程序员害怕使用“本机”HTML 标签......

Use:

用:

<button id="btnSubmit" runat="server" class="myButton" 
    onserverclick="btnSubmit_Click">Hello</button>

This usually works perfectly fine and everybody is happy in my team.

这通常工作得很好,我的团队中的每个人都很开心。