如何使用ASP.NET的button标签?

我想在ASP.NET网站中使用更新的<button>标签,其中包括允许使用CSS样式的文本并在button内embeddedgraphics。 asp:Button控件呈现为<input type="button"> ,有什么办法可以将一个预先存在的控件呈现给<button>

从我读过的有一个不兼容IE发布button的标记,而不是button位于<form>内的值属性,但在ASP.NET中,它将使用onclick事件来触发__doPostBack无论如何,所以我不认为这会是一个问题。

有什么理由不能使用这个吗? 如果没有,你将如何去支持与ASP:button,或基于它的新的服务器控制? 如果可以避免,我宁愿不写我自己的服务器控件。


起初, <button runat="server">解决scheme工作,但我立即遇到一个情况,需要有一个CommandName属性,HtmlButton控件没有。 看起来我需要创build一个从Buttoninheritance的控件。

我需要做什么来覆盖渲染方法,并使其呈现我想要的?


UPDATE

DanHerbert的回答使我有兴趣再次find解决办法,所以我花了更多的时间在这方面进行研究。

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

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

丹的解决scheme,因为它的问题是标签的innerhtml被放置到值属性,这会导致回发validation错误。 一个相关的问题是,即使你正确地呈现了value属性,IE的braindead实现的<button>标签发布的innerhtml而不是价值。 所以,这个任何实现都需要重写AddAttributesToRender方法,以便正确呈现值属性,并且还为IE提供某种解决方法,所以它不会完全搞砸回发。

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

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

ModernButton.cs

这呈现为一个正确的HTML <button>具有正确的值,但它不能与ASP.Net PostBack系统一起使用。 我写了一些我需要提供Command事件,但它不会触发。

当用一个普通的asp:Button检查这个button时,它们看起来与我所需要的不同。 所以我不确定在这种情况下ASP.Net如何连接Command事件。

另外一个问题是,嵌套的服务器控件不能被渲染(你可以看到ParseChildren(false)属性)。 在渲染过程中将直接的html文本注入控件非常容易,但是如何支持嵌套的服务器控件呢?

这是一个古老的问题,但对于我们这些仍然不得不维护ASP.NET Web窗体应用程序的人来说,我自己也尝试在内置button控件中包含Bootstrap字形。

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

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

我需要这个标记由服务器控件呈现,所以我着手寻找选项。

按键

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

LinkBut​​ton( 赞成Tsvetomir Tsonev的答案 )

资源

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

产量

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

优点

  • 看起来不错
  • Command事件; CommandNameCommandArgument属性

缺点

  • 呈现<a>而不是<button>
  • 渲染并依赖于强大的JavaScript

HtmlButton(相信菲利普的答案 )

资源

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

结果

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

优点

  • 看起来不错
  • 呈现正确的<button>元素

缺点

  • 没有Command事件; 没有CommandNameCommandArgument属性
  • 渲染并依赖强大的JavaScript处理其ServerClick事件

在这一点上,显然没有任何内置的控件看起来合适,所以下一个合理的步骤是尝试并修改它们以实现所需的function。

自定义控制( 丹·赫伯特的答案 )

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

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

我已经把课程剥离到了最低限度,并且重构了它,以尽可能less的代码实现相同的function。 我还添加了一些改进。 即:

  • 删除PersistChildren属性(似乎没有必要)
  • 删除TagName覆盖(似乎不必要)
  • Text删除HTML解码(基类已经处理了这个)
  • 保持OnPreRender完好; 重写AddParsedSubObject (简单)
  • 简化RenderContents覆盖
  • 添加一个Value属性(见下面)
  • 添加一个名字空间(包含一个@ Register指令的样本)
  • 添加必要的using指令

Value属性只是访问旧的Text属性。 这是因为本地Button控件总是呈现一个value属性(以Text为值)。 由于value<button>元素的有效属性,我决定为它包含一个属性。

资源

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

产量

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

优点

  • 看起来不错
  • 渲染一个正确的<button>元素
  • Command事件; CommandNameCommandArgument属性
  • 不渲染或依赖强大的JavaScript

缺点

  • 没有(除了不是一个内置的控制)

虽然你说使用[button runat =“server”]并不是一个好的解决scheme,但重要的是要提到它 – 许多.NET程序员害怕使用“native”HTML标签。

使用:

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

这通常工作得很好,每个人都为我的团队感到高兴。

我偶然发现了同样的问题。 我结束了使用Reflector找出如何实际呈现ASP.NET Button控件。 事实certificate很容易改变。

这真的只是重写Button类的TagNameTagKey属性。 完成之后,您只需确保您手动呈现button的内容,因为原始的Button类从未拥有要呈现的内容,并且如果不呈现内容,控件将呈现无文本button。

更新:

可以通过inheritance对Button控件做一些小的修改,并且仍然可以很好地工作。 这个解决scheme消除了为OnCommand实现自己的事件处理程序的需要(尽pipe如果你想学习如何做,我可以告诉你如何处理)。 它也解决了提交一个具有标记的值的问题,除了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); } } 

要使用此控件,您有几个选项。 一种是将控件直接放在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> 

您也可以将控件添加到代码隐藏button的控件集合中。

 // 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()); 

我不知道这两个选项的组合有多好,因为我没有testing过。

这个控件现在唯一的缺点是我不认为它会记住你的控件在PostBacks上。 我没有testing过,所以它可能已经工作,但我怀疑它。 你需要添加一些ViewStatepipe理代码来处理跨越PostBacks的子控件,但是这可能不是你的问题。 添加ViewState支持不是非常难,尽pipe如果需要,可以很容易地添加。

你可以创build一个新的控件,从Buttoninheritance,重写render方法,或者使用.browser文件覆盖站点中的所有button,类似于CSS友好的东西为TreeView控件工作的方式。

您可以使用本文中讨论的Button.UseSubmitBehavior属性来将ASP.NET Button控件渲染为button 。


编辑:对不起。这就是我在午休时偷看问题。 有没有理由不使用<button runat =“server”>标签或HtmlButton ?

我会去与LinkBut​​ton,并适当的样式与CSS。

我一直在努力整天 – 我的自定义<button/>生成的控件不能正常工作:

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

会发生什么是.Net添加一个name属性:

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

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

治愈的方法是破解那个name属性。 但我还没有想出来。