Как выбрать элемент по классу вместо идентификатора в ASP.NET? - PullRequest
17 голосов
/ 04 мая 2010

У меня есть несколько разбросанных <p> элементов на странице aspx, которые я группирую, используя класс, подобный этому - <p class="instructions" runat="server">

В моем коде, используя C #, я хочу скрыть эти элементы, используя что-то вроде instructions.Visible = false;

Однако я понимаю, что могу делать это только в коде, если использую идентификатор, но это приведет к неверному селектору HTML / CSS, поскольку у вас не может быть нескольких идентификаторов с одинаковым именем идентификатора ...

В качестве альтернативы есть ли другой способ сгруппировать элементы управления, если не по классу?

РЕДАКТИРОВАТЬ: я не могу использовать JavaScript, поэтому выбор должен быть сделан в C # codebehind / ASP.NET

Ответы [ 9 ]

19 голосов
/ 04 мая 2010

Все довольно просто. В вашем 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");
}

Codebehind будет автоматически подключен к обработчику событий PreRender в вашем классе. Это приводит отправителя к элементу управления и устанавливает его видимость в зависимости от класса css. Вам просто нужно настроить теги, и вам не нужно много кода, проходящего через вашу контрольную коллекцию.

14 голосов
/ 04 мая 2010

Помимо группировки всех элементов управления в один контейнерный элемент управления, не существует простого способа найти группу элементов управления с данным свойством в коде на стороне сервера ASP.NET.

На стороне клиента вы можете использовать что-то вроде jQuery , чтобы найти эти элементы и скрыть их:

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

Я бы, вероятно, сделал это в ответ, когда страница полностью загружена:

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

Недостатком скрытия элементов в Javascript является то, что если данных достаточно, это может занять секунду и вызвать мерцание контента. Другое отличие состоит в том, что сокрытие контента на стороне клиента не удаляет его из DOM - контент там просто скрыт. Скрытие элементов управления на стороне сервера предотвращает передачу их содержимого в HTML.

Делать то же самое в C # немного сложнее - требуется рекурсивный обход дерева управления и поиск элементов в коллекции Control, которые соответствуют. Это достаточно распространенная операция, поэтому полезная функция полезна. Синтаксис итератора C # (возвращение урожая) помогает сделать это чистым:

// 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;
}
5 голосов
/ 30 октября 2012

Я хочу ответить на один из первых ответов - где мы используем рекурсию, чтобы пройти через все элементы управления. Прежде всего, не должны ли мы возвращаться к дочерним элементам? Я не посмотрел внимательно на код и увидел, что мы продолжали вызывать метод рекурсивно по «c», а не «child». Во-вторых, я обнаружил, что ни один из элементов на моей веб-странице не может быть приведен к 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.

3 голосов
/ 04 мая 2010

Если вы включаете ядро ​​JQuery, все, что вам нужно сделать, это зарегистрировать этот скрипт на своей странице:

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

Используется селектор класса JQuery http://api.jquery.com/class-selector/

1 голос
/ 22 ноября 2016

Я протестировал решение 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 голос
/ 04 мая 2010

Опираясь на решение Себастьяна П. Р. Гингтера, я сделал вот что, хотя все еще чувствую себя немного взломанным, учитывая, что мне нужно использовать WebControl на основе MS вместо того, чтобы отказаться от более простого элемента управления HTML.

В 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 голос
/ 04 мая 2010

<asp:Panel> подход

Вы можете поместить их все внутрь, если они последовательно помещены в вашу форму. Таким образом, вы можете легко переключать свойство .Visible панели, чтобы скрыть фрагменты формы.

JavaScript подход

Вы можете использовать ClientScriptManager.RegisterStartupScript() для генерации JavaScript, а затем использовать jQuery для скрытия по классам.

1 голос
/ 04 мая 2010

Вы можете создать рекурсивную функцию для обхода массива элементов управления страниц, проверяя атрибут CssClass для каждого элемента управления и устанавливая его при необходимости.

0 голосов
/ 04 мая 2010

Вы можете использовать JQuery Class Name Selector для этой цели.
Другое решение состоит в том, чтобы сохранить те же идентификаторы, а не создавать элементы управления на стороне сервера. в JavaScript используйте document.getElementById для получения элементов управления, в вашем случае вы получите массив, который будет содержать все элементы управления, имеющие одинаковые идентификаторы. Выполните итерацию по этим элементам управления и соответственно установите их атрибуты отображения.

...