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

Ada*_*sek 62 html c# asp.net htmlbutton

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

从我读过的内容来看,当按钮位于a中时<form>,IE发布按钮的标记而不是value属性是不兼容的,但是在ASP.NET中它将使用onclick事件来触发__doPostBack,所以我不喜欢认为这将是一个问题.

我有什么理由不这样做吗?如果没有,您将如何使用asp:Button或基于它的新服务器控件来支持它?如果可以避免,我宁愿不编写自己的服务器控件.


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

我需要做什么才能覆盖渲染方法并使其呈现我想要的东西?


UPDATE

DanHerbert的回复让我有兴趣再次寻找解决方案,所以我花了一些时间来研究它.

首先,有一种更容易的方法来重载TagName:

public ModernButton() : base(HtmlTextWriterTag.Button)
{
}
Run Code Online (Sandbox Code Playgroud)

Dan的解决方案存在的问题是标记的innerhtml被放置在value属性中,这会导致回发时出现验证错误.一个相关的问题是,即使你正确地渲染value属性,IE的<button>标签的braindead实现也会发布innerhtml 而不是值.因此,任何实现都需要覆盖AddAttributesToRender方法才能正确呈现value属性,并且还为IE提供某种解决方法,因此它不会完全搞砸回发.

如果要利用数据绑定控件的CommandName/CommandArgument属性,IE问题可能是不可克服的.希望有人可以为此建议解决方法.

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

ModernButton.cs

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

当用常规的asp:Button并排检查这个按钮时,它们看起来与我需要的差异相同.所以我不确定Command在这种情况下ASP.Net是如何连接事件的.

另一个问题是,不呈现嵌套的服务器控件(正如您可以使用ParseChildren(false)属性看到的那样).在渲染过程中将文字html文本注入控件非常容易,但是如何允许支持嵌套服务器控件呢?

Phi*_*ppe 43

虽然你说使用[button runat ="server"]并不是一个足够好的解决方案,但重要的是要提到它 - 很多.NET程序员都害怕使用"本机"HTML标签......

使用:

<button id="btnSubmit" runat="server" class="myButton" 
    onserverclick="btnSubmit_Click">Hello</button>
Run Code Online (Sandbox Code Playgroud)

这通常很好,每个人都很高兴我的团队.

  • 您可以在此类控件上添加自定义属性,并轻松地在代码后面检索值. (5认同)
  • 是的,虽然它不等同于asp:button,但确实有效,因为你失去了很多功能.在我的情况下,按钮位于数据绑定控件内,因此没有CommandName和CommandArgument它的实用程序非常有限. (3认同)
  • 这似乎打破了causevalidation ="false" (2认同)

Dan*_*zzi 36

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

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

<button class="btn btn-default">
    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
    Search
</button>
Run Code Online (Sandbox Code Playgroud)

我需要这个标记由服务器控件呈现,所以我开始寻找选项.

按键

这将是第一个合乎逻辑的步骤,但是 - 这个问题解释了 - 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>
Run Code Online (Sandbox Code Playgroud)

产量

<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>
Run Code Online (Sandbox Code Playgroud)

优点

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

缺点

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

HtmlButton(归功于Philippe的回答)

资源

<button runat="server" id="uxSearch" class="btn btn-default">
    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
    Search
</button>
Run Code Online (Sandbox Code Playgroud)

结果

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

优点

  • 看起来不错
  • 渲染适当的<button>元素

缺点

  • 没有Command事件; 没有CommandNameCommandArgument属性
  • 渲染并依赖于突兀的JavaScript来处理它的ServerClick事件

此时很明显,没有一个内置控件看起来合适,所以下一个逻辑步骤是尝试并修改它们以实现所需的功能.

定制控制(丹·赫伯特的回答)

注意:这是基于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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经将类剥离到最低限度,并重构它以尽可能少的代码实现相同的功能.我还添加了一些改进.即:

  • 删除PersistChildren属性(似乎没必要)
  • 删除TagName覆盖(似乎没必要)
  • 删除HTML解码Text(基类已处理此问题)
  • 保持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>
Run Code Online (Sandbox Code Playgroud)

产量

<button type="submit" name="uxSearch" value="Foo" id="uxSearch" class="btn btn-default">
    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
    Search
</button>
Run Code Online (Sandbox Code Playgroud)

优点

  • 看起来不错
  • 呈现适当的<button>元素
  • Command事件; CommandNameCommandArgument属性
  • 不呈现或依赖于突兀的JavaScript

缺点

  • 无(除非不是内置控件)


Dan*_*ert 29

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

它实际上只是归结为压倒一切的TagName,并TagKey在属性Button类.完成后,您只需确保手动呈现按钮的内容,因为原始Button类从未有要呈现的内容,如果不呈现内容,控件将呈现无文本按钮.

更新:

可以通过继承对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);
    }
}
Run Code Online (Sandbox Code Playgroud)

要使用此控件,您有几个选项.一种是将控件直接放入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>
Run Code Online (Sandbox Code Playgroud)

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

// 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());
Run Code Online (Sandbox Code Playgroud)

我不知道这两个选项的组合有多好,因为我还没有测试过.

这个控件现在唯一的缺点就是我不认为它会记住你在PostBacks中的控件.我没有对此进行测试,因此它可能已经有效,但我对此表示怀疑.你需要为PostBacks中的子控件添加一些ViewState管理代码,但是这对你来说可能不是问题.添加ViewState支持应该不是非常难以做到,尽管如果需要可以轻松添加.

  • 你已经到了一半,但使用按钮标签的一个主要原因是能够在其中添加标记,例如嵌入的图像.这似乎是最难的部分,允许服务器控件内的内容.我还没有找到如何做到的描述. (2认同)

Ste*_*ins 6

您可以创建一个新的控件,继承Button,并覆盖render方法,或使用.browser文件覆盖站点中的所有Buttons,类似于CSS Friendly东西对TreeView控件的工作方式等.


Way*_*yne 6

您可以使用本文中讨论的有关将ASP.NET Button控件呈现为按钮Button.UseSubmitBehavior属性.


编辑:对不起..这就是我在午休时间提到的问题.你有没有理由不使用<button runat ="server">标签或HtmlButton