web-dev-qa-db-ja.com

ASP.NETでIDではなくクラスで要素を選択するにはどうすればよいですか?

Aspxページにいくつかの<p>要素が散在しており、そのようなクラスを使用してグループ化しています-<p class="instructions" runat="server">

私のコードビハインドでは、C#を使用して、instructions.Visible = false;のようなものを使用してこれらの要素を非表示にします

ただし、IDを使用する場合にのみコードビハインドでこれを実行できますが、同じID名を持つ複数のIDを持つことができないため、無効なHTML/CSSセレクターになります...

あるいは、クラスごとではない場合、コントロールをグループ化する別の方法はありますか?

編集:JavaScriptを使用できないため、選択はC#codebehind /ASP.NETで行う必要があります

17
firedrawndagger

すべてのコントロールを単一のコンテナーコントロールにグループ化する以外に、ASP.NETサーバー側コードでいくつかのプロパティが指定されたコントロールのグループを見つける簡単な方法はありません。

クライアント側では、 jQuery のようなものを使用して、これらの要素を見つけて非表示にすることができます。

$(".instructions").hide();

ページが完全に読み込まれたときに、おそらくこれを実行します。

$(document).ready(function() { 
   $(".instructions").hide(); 
});

Javascriptで要素を非表示にすることの欠点の1つは、十分なデータがある場合、1秒かかり、コンテンツがちらつく可能性があることです。もう1つの違いは、コンテンツをクライアント側で非表示にしても、DOMから削除されないことです。コンテンツは非表示になっているだけです。コントロールをサーバー側で非表示にすると、コンテンツがHTMLに出力されるのを防ぐことができます。

C#で同じことを行うのは少し難しいです。これには、コントロールツリーを再帰的にトラバースし、一致するControlコレクション内の要素を探す必要があります。これは、ユーティリティ関数が役立つ十分に一般的な操作です。 C#イテレータ構文 (yield return)は、これをクリーンにするのに役立ちます。

// utility method to recursively find controls matching a predicate
IEnumerable<Control> FindRecursive( Control c, Func<Control,bool> predicate )
{
    if( predicate( c ) )
        yield return c;

    foreach( var child in c.Controls )
    {
        if( predicate( c ) )
            yield return c;
    }

    foreach( var child in c.Controls )
        foreach( var match in FindRecursive( c, predicate ) )
           yield return match;
}

// use the utility method to find matching controls...
FindRecursive( Page, c => (c is WebControl) && 
                          ((WebControl)c).CssClass == "instructions" );

コントロールを非表示にするのは比較的簡単です。

foreach( WebControl c in FindRecursive( Page, c => (c is WebControl) && 
                           ((WebControl)c).CssClass == "instructions" ) )
{
    c.Visible = false;
}
14
LBushkin

とても簡単です。 ASPXの場合:

<p class="instructions" runat="server" OnPreRender="Paragraph_PreRender">

コードビハインド:

protected void Paragraph_PreRender(object sender; EventArgs e)
{
  Control paragraph = (Control)sender;
  paragraph.Visible = !paragraph.CssClass.Contains("instructions");
}

コードビハインドは、クラスのPreRenderイベントハンドラーに自動的に接続されます。これにより、送信者がコントロールにキャストされ、その可視性がcssクラスに依存するように設定されます。タグを調整するだけで、コントロールコレクションをトラバースする多くのコードは必要ありません。

最初の答えの1つに応答したいと思います。ここでは、再帰を使用してすべてのコントロールを実行しています。まず、子アイテムを繰り返してはいけませんか?コードを詳しく調べなかったので、「子」ではなく「c」でメソッドを再帰的に呼び出し続けていることがわかりました。次に、自分のWebページのどのアイテムもWebControlにキャストできず、HtmlGenericControlにのみキャストできることがわかりました。

編集後、私はこれを持っていました:

    // utility method to recursively find controls matching a predicate
    IEnumerable<Control> FindRecursive( Control c, Func<Control,bool> predicate )
    {
        if( predicate( c ) )
            yield return c;

        foreach (var child in c.Controls) {
            if (predicate((Control)child)) {
               yield return (Control)child;
            }
        }

        foreach( var child in c.Controls )
            foreach( var match in FindRecursive( (Control)child, predicate ) )
               yield return match;
    }

    foreach (Control c in FindRecursive(Page, c => (c is HtmlGenericControl) &&
         ((HtmlGenericControl)c).Attributes["ishidden"] == "1"))
    {
         c.Visible = false;
    }

「CssClass」を使用できなかったことに注意してください。これを機能させるには、独自の属性(「ishidden」)を設定する必要がありました。

<div runat="server" ishidden="1"> ... </div>

ASP.NET Framework 2.0/3.0 /3.5を使用しています。

5
blackcatweb

JQueryコアを含める場合は、このスクリプトをページに登録するだけです。

<script>
 $(document).ready(function() {
    $(".instructions").hide();
 });
</script>

JQueryクラスセレクターを使用します http://api.jquery.com/class-selector/

3
Daniel Dyson

各コントロールのCssClass属性を確認し、必要に応じて設定して、ページコントロール配列をウォークする再帰関数を作成できます。

1
Mesh

_<asp:Panel>_アプローチ

それらがあなたのフォームに連続して配置される場合、あなたはそれらをすべて中に入れることができます。これにより、パネルの.Visibleプロパティを簡単に切り替えて、フォームのチャンクを非表示にできます。

JavaScriptアプローチ

ClientScriptManager.RegisterStartupScript()を使用してJavaScriptを発行し、jQueryを使用してクラスで非表示にすることができます。

1
rtpHarry

Sebastian P.R. Gingterソリューションに基づいて、これが私が行ったことですが、より単純なHTMLコントロールをオプトアウトする代わりに、MSベースのWebControlを使用する必要があることを考えると、まだ少しハックを感じます。

C#の場合:

protected void Paragraph_PreRender(object sender, EventArgs e) 
{
  WebControl paragraph = (WebControl)sender;
  paragraph.Visible = !paragraph.CssClass.Contains("instructions"); 
} 

Aspxの場合:

 <asp:Label ID="Label1" CssClass="instructions" runat="server" Text="Label" onPreRender="Paragraph_PreRender"></asp:Label>
1
firedrawndagger

Blackcatwebのソリューションをテストしました。重複を返すので、修正してWebControlsのメソッドを追加しました。私のコードは以下の通りです。クラスセットattrName = "class"で検索するには:

    /// <summary>
    /// Find controls
    /// </summary>
    /// <param name="c">Control</param>
    /// <param name="predicate">Function</param>
    /// <returns>Control's</returns>
    public static IEnumerable<Control> FindRecursive(Control c, Func<Control, bool> predicate)
    {
        if (predicate(c))
        {
            yield return c;
        }

        foreach (Control child in c.Controls)
        {
            foreach (Control founded in FindRecursive(child, predicate))
            {
                yield return founded;
            }
        }
    }

    /// <summary>
    /// Find WebControls by attr
    /// </summary>
    /// <param name="c">Control</param>
    /// <returns>WebControls</returns>
    public static IEnumerable<WebControl> FindWebControlsByAttr(Control baseControl, string attrName, string attrValue)
    {
        foreach (WebControl c in FindRecursive(baseControl, c => (c is WebControl)
            && !string.IsNullOrEmpty(((WebControl)c).Attributes[attrName])
            && ((WebControl)c).Attributes[attrName].Contains(attrValue)))
        {
            yield return c;
        }
    }

    /// <summary>
    /// Find HtmlGenericControls by attr
    /// </summary>
    /// <param name="c">Control</param>
    /// <returns>HtmlGenericControls</returns>
    public static IEnumerable<HtmlGenericControl> FindControlsByAttr(Control baseControl, string attrName, string attrValue)
    {
        foreach (HtmlGenericControl c in FindRecursive(baseControl, c => (c is HtmlGenericControl)
            && !string.IsNullOrEmpty(((HtmlGenericControl)c).Attributes[attrName])
            && ((HtmlGenericControl)c).Attributes[attrName].Contains(attrValue)))
        {
            yield return c;
        }
    }
1
Stas V

この目的のために JQuery Class Name Selector を使用できます。
別の解決策は、同じIDを維持し、コントロールをサーバー側にしないことです。 JavaScriptでは、document.getElementByIdを使用してコントロールを取得します。この場合、同じIDを持つすべてのコントロールを保持する配列を取得します。これらのコントロールを繰り返し、それに応じて表示属性を設定します。

0
MUS