63

ASP.NET Web サイトで新しいタグを使用したいと考えてい<button>ます。これにより、特に、CSS スタイルのテキストとボタン内のグラフィックの埋め込みが可能になります。asp:Button コントロールは としてレンダリングされます。<input type="button">既存のコントロールを にレンダリングする方法はあります<button>か?

私が読んだことから、ボタンが 内にある場合、値属性の代わりにボタンのマークアップを投稿する IE との非互換性があります<form>が、ASP.NET では onclick イベントを使用してとにかく __doPostBack を起動するので、私はしません。これが問題になるとは思わない。

これを使用してはいけない理由はありますか? そうでない場合、asp:Button、またはそれに基づく新しいサーバー コントロールでどのようにサポートしますか? 回避できる場合は、独自のサーバー コントロールを記述しないことをお勧めします。


最初はこの<button runat="server">ソリューションは機能していましたが、すぐに HtmlButton コントロールにない CommandName プロパティが必要な状況に遭遇しました。結局、Button から継承したコントロールを作成する必要がありそうです。

render メソッドをオーバーライドして、必要なものをレンダリングするにはどうすればよいですか?


アップデート

DanHerbert の返信により、これに対する解決策を再び見つけることに興味が湧いたので、もう少し時間をかけて取り組みました。

まず、TagName をオーバーロードするはるかに簡単な方法があります。

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

Dan のソリューションの問題点は、タグの innerhtml が value プロパティに配置され、ポストバック時に検証エラーが発生することです。関連する問題として、値のプロパティを正しくレンダリングしたとしても、IE の脳死状態の<button>タグの実装では、値の代わりに innerhtml がポストされます。そのため、これを実装する場合は、値のプロパティを正しくレンダリングするために AddAttributesToRender メソッドをオーバーライドする必要があります。また、ポストバックを完全に台無しにしないように、IE に何らかの回避策を提供する必要もあります。

データバインドされたコントロールの CommandName/CommandArgument プロパティを利用したい場合、IE の問題は解決できない場合があります。うまくいけば、誰かがこれに対する回避策を提案できます。

私はレンダリングを進めました:

ModernButton.cs

これは正しい値を持つ適切な html としてレンダリングされ<button>ますが、ASP.Net PostBack システムでは機能しません。イベントを提供するために必要なものをいくつか書きましたが、起動Commandしません。

このボタンを通常の asp:Button と並べて調べると、必要な違い以外は同じように見えます。したがってCommand、この場合、ASP.Net がイベントをどのように配線しているかはわかりません。

もう 1 つの問題は、入れ子になったサーバー コントロールがレンダリングされないことです (ParseChildren(false) 属性でわかるように)。レンダリング中にリテラル HTML テキストをコントロールに挿入するのは非常に簡単ですが、ネストされたサーバー コントロールのサポートをどのように許可しますか?

4

7 に答える 7

44

[button runat="server"] を使用することは十分な解決策ではないとおっしゃっていますが、それについて言及することは重要です - 多くの .NET プログラマーは「ネイティブ」HTML タグの使用を恐れています...

使用する:

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

これは通常、問題なく機能し、私のチームでは全員が満足しています。

于 2009-07-23T12:56:32.603 に答える
38

これは古い質問ですが、ASP.NET Web フォーム アプリケーションを維持しなければならない不運な私たちにとって、組み込みのボタン コントロール内に 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イベントなし。CommandNameまたはCommandArgumentプロパティ_
  • ServerClickそのイベントを処理するために目障りな JavaScript をレンダリングして依存します

この時点で、適切な組み込みコントロールがないように見えることは明らかなので、次の論理的なステップは、必要な機能を実現するためにそれらを変更してみることです。

カスタム コントロール ( Dan Herbert の回答へのクレジット)

注: これは Dan のコードに基づいているため、すべてのクレジットは 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);
        }
    }
}

私はクラスを最小限にまで取り除き、可能な限り少ないコードで同じ機能を実現するようにリファクタリングしました。また、いくつかの改善を追加しました。すなわち:

  • 属性を削除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>

出力

<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 をレンダリングしない、または依存しない

短所

  • なし (組み込みコントロールでないこと以外)
于 2015-08-07T13:36:01.843 に答える
29

まったく同じものを探しているあなたの質問に出くわしました。結局、ASP.NETコントロールが実際にどのようにレンダリングされるかを把握するために、Reflectorを使用することになりました。Button本当に簡単に変更できることがわかりました。

実際には、クラスの プロパティTagNameTagKeyプロパティをオーバーライドするだけです。元のクラスにはレンダリングするコンテンツがなく、コンテンツをレンダリングしない場合、コントロールはテキストなしのボタンをレンダリングするためButton、ボタンのコンテンツを手動でレンダリングする必要があります。Button

アップデート:

継承によって Button コントロールにいくつかの小さな変更を加えることができ、それでもかなりうまく機能します。このソリューションにより、OnCommand 用に独自のイベント ハンドラーを実装する必要がなくなります (ただし、その方法を知りたい場合は、その処理方法をお見せします)。おそらく IE を除いて、マークアップを含む値を送信する際の問題も修正されます。ただし、IE のボタン タグの不適切な実装を修正する方法はまだわかりません。これは、回避できない本当に技術的な制限である可能性があります...

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

このコントロールを使用するには、いくつかのオプションがあります。1 つは、コントロールを 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>

コード ビハインドでボタンのコントロール コレクションにコントロールを追加することもできます。

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

テストしていないため、両方のオプションの組み合わせがどれほどうまく機能するかはわかりません。

このコントロールの現時点での唯一の欠点は、PostBacks 全体でコントロールを記憶できないことです。私はこれをテストしていないので、すでに機能している可能性がありますが、そうではないかもしれません。PostBacks 全体でサブコントロールを処理するには、ViewState 管理コードを追加する必要があると思いますが、これはおそらく問題にはなりません。ViewState のサポートを追加することは、それほど難しいことではありませんが、必要に応じて簡単に追加できます。

于 2009-02-22T00:08:16.807 に答える
6

Button から継承して新しいコントロールを作成し、render メソッドをオーバーライドするか、.browser ファイルを使用してサイト内のすべてのボタンをオーバーライドすることができます。

于 2008-10-09T14:41:10.853 に答える
6

ボタンとしての ASP.NET ボタン コントロールのレンダリングに関するこの記事で説明されているように、 Button.UseSubmitBehaviorプロパティを使用できます。


編集:申し訳ありません..それは私が昼休みに質問をスキミングするために得たものです. <button runat="server"> タグやHtmlButtonだけを使用しない理由はありますか?

于 2008-10-09T15:59:18.497 に答える
2

LinkBut​​ton を使用し、必要に応じて CSS でスタイルを設定します。

于 2008-10-09T14:28:33.937 に答える
1

私はこれに一日中苦労してきました-カスタム<button/>生成されたコントロールが機能しません:

System.Web.HttpRequestValidationException: 潜在的に危険な Request.Form 値がクライアントから検出されました

何が起こるかというと、.Net がname属性を追加することです:

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

このname属性は、IE 6 および IE 7 を使用するとサーバー エラーをスローします。他のブラウザー (Opera、IE 8、Firefox、Safari) ではすべて正常に動作します。

name治療法は、その属性をハッキングすることです。それでも私はそれを理解していません。

于 2009-06-10T13:21:09.907 に答える