如何在 ASP.NET 中按类而不是 ID 选择元素?
Posted
技术标签:
【中文标题】如何在 ASP.NET 中按类而不是 ID 选择元素?【英文标题】:How to select an element by Class instead of ID in ASP.NET? 【发布时间】: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 中完成
【问题讨论】:
【参考方案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】:
<asp:Panel>
接近
如果它们连续放置在您的表单中,您可以将它们全部放在 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 的控件。遍历这些控件并相应地设置它们的显示属性。
【讨论】:
以上是关于如何在 ASP.NET 中按类而不是 ID 选择元素?的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core 依赖注入单个聚合类而不是多个单独的构造函数注入
使用 WebDriver 在 codeceptJS 中按类获取元素