【问题标题】:How to select an element by Class instead of ID in ASP.NET?如何在 ASP.NET 中按类而不是 ID 选择元素?
【发布时间】:2011-02-15 12:31:29
【问题描述】:

我在 aspx 页面上有一些分散的 <p> 元素,我使用这样的类将它们组合在一起 - <p class="instructions" runat="server">

在我的代码后面,使用 C# 我想隐藏这些元素,使用类似的东西 instructions.Visible = false;

但是我意识到如果我使用 ID,我只能在代码隐藏中执行此操作,但这会导致 HTML/CSS 选择器无效,因为您不能拥有多个 ID 名称相同的 ID...

如果不是按类,还有其他方法可以对控件进行分组吗?

编辑:我不能使用 JavaScript,所以选择必须在 C# codebehind/ASP.NET 中完成

【问题讨论】:

    标签: c# asp.net select css-selectors selection


    【解决方案1】:

    事情很简单。在您的 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 事件处理程序。这会将发送者转换为控件,并将其 Visibility 设置为依赖于 css 类。 您只需要调整标签,不需要大量代码遍历您的控件集合。

    【讨论】:

    • 这解决了我的问题。由于我是动态创建对象,因此我以这种方式分配函数= thumbnail.PreRender += funcThumbnail_PreRender;一切都完美无缺!
    • 绝对是在后端显示/隐藏控件的最简单和最干净的方法。谢谢!
    【解决方案2】:

    除了将所有控件分组到一个容器控件中之外,没有简单的方法可以在 ASP.NET 服务器端代码中找到给定某些属性的一组控件。

    在客户端,您可以使用 jQuery 之类的东西来查找这些元素并隐藏它们:

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

    当页面完全加载时,我可能会这样做:

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

    在 Javascript 中隐藏元素的一个缺点是,如果有足够的数据,它可能需要一秒钟的时间并导致内容闪烁。另一个区别是隐藏内容客户端不会从 DOM 中删除它 - 内容只是隐藏在那里。在服务器端隐藏控件可防止其内容甚至被发送到 HTML。

    在 C# 中做同样的事情有点困难——它需要递归地遍历控制树并在 Control 集合中寻找匹配的元素。这是一个足够常见的操作,实用函数很有用。 C# iterator syntax(收益回报)有助于清理:

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

    【讨论】:

    • 我喜欢这个主意。使方法成为扩展方法,然后你可以简单地去: Page.FindRecursive(c => (c is WebControl) && ((WebControl)c).CssClass == "instructions")).ForEach(c => ((WebControl )c).Visible = false);
    • 这看起来很棒,C# 解决方案正是我想要的。
    • 也许再看看我的回答。由于不需要遍历控件集合,它的代码更少,而且不那么昂贵。当然,您需要调整 aspx 中的

      元素作为缺点。

    • 这段代码会导致溢出异常,不应该使用。此外,它的缺陷在于它不遍历子控件(在每个 foreach 循环中,子控件都是未使用的)。 (见下面的黑猫回答)
    • 鉴于这是公认的答案并且几乎是正确的,也许@LBushkin 可以更正它,这样就无需进一步阅读以获得几乎相同的东西。 (即它是否只需要将child 传递到嵌套的foreach 而不是传递c?)
    【解决方案3】:

    我想回答第一个答案 - 我们使用递归来遍历所有控件。首先,我们不应该递归子项吗?我没有仔细看代码,发现我们一直在“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 框架 2.0/3.0/3.5。

    【讨论】:

      【解决方案4】:

      如果你包含 JQuery 核心,你所要做的就是在你的页面上注册这个脚本:

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

      它使用 JQuery 类选择器http://api.jquery.com/class-selector/

      【讨论】:

      • 我喜欢这个解决方案 - 我主要担心我不能使用 JavaScript,因为某些客户端启用了 JavaScript。
      【解决方案5】:

      您可以创建一个递归函数来遍历页面控件数组,检查每个控件的 CssClass 属性并根据需要进行设置。

      【讨论】:

      • 这基本上是当您执行 getElementsByTagName 或使用 jquery 选择器按类选择时在客户端上发生的情况。不是遍历 DOM,而是遍历 asp.net 控制树。
      • 我打算输入一个粗略的代码示例 - 但 LBushkin 发布的方式比我的要好!
      【解决方案6】:

      &lt;asp:Panel&gt; 接近

      如果它们连续放置在您的表单中,您可以将它们全部放在 an 中。这样您就可以轻松切换面板的 .Visible 属性来隐藏表单的块。

      JavaScript 方法

      您可以使用ClientScriptManager.RegisterStartupScript() 发出 JavaScript,然后使用 jQuery 按类隐藏。

      【讨论】:

      • 很好的解决方案,不幸的是我不能使用 JS 并且我的段落分散 - 这就是为什么我用类标记它们。
      【解决方案7】:

      在 Sebastian P.R. Gingter 解决方案的基础上,这就是我所做的,尽管考虑到我必须使用基于 MS 的 WebControl 而不是选择更简单的 HTML 控件,但它仍然感觉有点像 hack。

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

      【讨论】:

        【解决方案8】:

        我已经测试了 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;
                }
            }
        

        【讨论】:

          【解决方案9】:

          您可以为此目的使用JQuery Class Name Selector
          另一种解决方案是保持相同的 ID,而不是使控件服务器端。在 JavaScript 中使用 document.getElementById 来获取控件,在您的情况下,您将获得一个数组,该数组将保存所有具有相同 ID 的控件。遍历这些控件并相应地设置它们的显示属性。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-03-15
            • 2013-12-31
            • 2012-10-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多