65.9K
CodeProject 正在变化。 阅读更多。
Home

GridView 悬停菜单

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.17/5 (13投票s)

2007年10月30日

6分钟阅读

viewsIcon

87718

一篇关于在 div 中的弹出菜单中显示 girdview 的行绑定命令字段的文章。

Screenshot - gridview1.jpg

引言

问题

场景 1

那么,我们在这里讨论什么呢?假设我们有一个 GridView,并且其中包含一些命令字段,如编辑、删除、导航到 URL 等。将所有这些命令(LinkButton 或 HyperLink)放在单独的列中,甚至放在一列中,看起来都会很笨拙。

场景 2

有时,我们可能希望根据行的数据显示某些命令。在我正在处理的页面中,我必须为 GridView 中的每一行显示打印、电子邮件、编辑和预览按钮。此外,并非所有行都具有相同的按钮。有些行无法编辑,有些行无法通过电子邮件发送(当没有电子邮件地址可供发送时)。

背景

如果大家检查过 AJAX 控件工具包,会发现它以一种简单而优雅的方式实现了这一点。点击此处查看 AJAX 悬停菜单的实际效果。场景 2 是我们代码与众不同的地方。

使用代码(继续阅读前请务必阅读)

假设您了解 GridView 及其相关事件,我将不再深入探讨如何实现此鼠标悬停弹出菜单。另外,我假设您熟悉 DIV 等 HTML 元素以及这些元素的位置。我使用的 JavaScript 支持方法非常简单易用且具有可扩展性。

解决方案

那么,我们如何同时实现本文开头讨论的两种功能,并使我们的 GridView 看起来更漂亮呢?好了,我们开始吧。

Screenshot - gridview2.jpg

上面的 GridView 是我们可能都见过并实现过的普通 GridView。它很普通,目前还没有实现命令字段。正如您所知,我们通常会在最后一列或第一列包含命令字段,如编辑(更新和取消)、删除等。

为了使此 GridView 具有本文开头第一个图像那样的外观,让我们先创建弹出菜单。在创建弹出菜单之前,请考虑要将其放置在哪里。我的意思是,您希望它在哪里弹出。我通常喜欢让弹出菜单显示在最后一列,并稍微向 GridView 内部移动(从第一张图中可以看出),这样它就会覆盖 GridView,但不会遮挡最后一列的内容。

<asp: templatefield headertext="Status"
<itemtemplate>
<asp:label id="lblStatus" Text='<%# Bind("Status")%>'/>
</asp:templatefield>
<div id="gridPopup" style="DISPLAY:none; Z-INDEX:101; POSITION: absolute; 
   HEIGHT:38px" runat="server">
<asp:linkbutton id="lbtngrdPrint" text="PRINT" runat="server" 
    commandargument='<%#Bind("Status")%>' commandname="Print" 
    causesvalidation="false"/>
<asp:linkbutton id="lbtngrdEmail" text="SEND" runat="server" 
    commandargument='<%#Bind("Status")%>' commandname="Email" 
    causesvalidation="false"/>
</div>
</itemtemplate>

现在,这是最后一列的模板。我将在其中添加我的 DIV 弹出菜单。如您所见,我目前在 DIV 中有两个 LinkButton。您可以根据需要添加任意数量的按钮。此外,您还可以为其应用样式,使其看起来更漂亮。这部分留给您。

如您所见,我将包含所有适用的菜单项(作为 LinkButton)的 DIV 标签放置在最后一列的 ItemTemplate 部分。请注意,我还设置了 DIV 标签的 z-index 和绝对定位。这对于 DIV 的定位至关重要。由于 DIV 位于 ItemTemplate 中,我可以将其绑定到 DataItem,甚至可以为其指定命令名称。

现在标记已经就绪,让我们编写一些客户端代码来切换 DIV 的可见性。

// Shows DIV popup commands for gridview

function ShowPopup(lbtn1,lbtn2, panel, gridviewRow)
{
    var link1 = document.getElementById(lbtn1);
    var link2 = document.getElementById(lbtn2);
    var pnl = document.getElementById(panel);
    var row= document.getElementById(gridviewRow);
    pnl.style.display = "block";

    row.style.backgroundImage = "url(../images/td_mouseover.gif)";
    if(link1 != null)
        link1.style.display = "block";
    if(link2 != null)
        link2.style.display = "block";
    pnl.style.backgroundImage = "url(../images/td_mouseover_inverted.gif)";
}

//Hides DIV popup commands for gridview

function HidePopup(lbtn1,lbtn2, panel, gridviewRow)
{
    var link1 = document.getElementById(lbtn1);
    var link2 = document.getElementById(lbtn2);

    var pnl = document.getElementById(panel);
    var row= document.getElementById(gridviewRow);
    row.style.backgroundImage="url(../images/spacer.gif)";
    pnl.style.display = "none";
    if(link1 != null)
        link1.style.display = "none";
    if(link2 != null)
        link2.style.display = "none";
}

理解此脚本非常简单。您在 ShowPopupHidePopup 两个函数中看到的参数将在下面描述:

  • lbtn1:LinkButton1。我只是这样命名,以便我知道它是我们菜单中的第一个按钮。记住要对其进行数据绑定,因为您将其放在 GridView 中。
  • lbtn2:LinkButton2。DIV 弹出菜单中的第二个 LinkButton。如我之前提到的,您可以在 DIV 中放置任意数量的控件(通常出于我们的目的,是按钮或超链接)。您所要做的就是将该控件的 ID 作为参数添加到 JavaScript 函数中,并将可见性设置为 'none' 或 'block'。
  • panel:我将 DIV 层称为 panel,因为它们本质上是相同的。您必须先打开和关闭 DIV(或我在这里称之为 panel)的可见性,然后再切换其中菜单项(LinkButton 和/或您可能拥有的任何其他控件)的可见性。

当然,最后一个参数是 GridView 行,在页面渲染时它被视为 <TD>。

自定义 DIV 弹出菜单中的菜单项

如果您看到新 GridView 的图像,它将显示打印和电子邮件选项。您可以在行的 mouseover 事件上将这些项的可见性设置为开或关。这些您已经知道了。现在,有趣的部分是,您可以根据行的值显示行特定的命令字段。这意味着,您可以只为某些行显示打印按钮,为某些行显示电子邮件按钮。当然,您可以对它们进行排列组合。我们该如何做呢?

好了,这是 GridView 的 Row Data Bound 事件。我们知道,当 GridView 行进行数据绑定时,会触发此事件。因此,这可能是设置行特定脚本和条件的最佳位置。

protected void
gvwMyReferrals_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        LinkButton lbtnGrdPrint = (LinkButton)e.Row.Cells[6].FindControl(
            "lbtnGrdPrint");
        LinkButton lbtnGrdEmail = (LinkButton)e.Row.Cells[6].FindControl(
            "lbtnGrdEmail");
        HtmlGenericControl panel = 
            (HtmlGenericControl)e.Row.Cells[6].FindControl(
            "gvwMyReferralsDiv");

        string showPopup = "ShowPopup('" + lbtnGrdPrint.ClientID + 
            "','" + lbtnGrdEmail.ClientID + "','" + 
            panel.ClientID + "','"+e.Row.ClientID+"')";
        string hidePopup = "HidePopup('" + lbtnGrdPrint.ClientID + 
            "','" + lbtnGrdEmail.ClientID
            + "','" + panel.ClientID + "','" + 
            e.Row.ClientID + "')";
            e.Row.Attributes.Add("onmouseover", 
            "javascript:"+showPopup);
        e.Row.Attributes.Add("onmouseout", 
            "javascript:" +hidePopup);
    }
}

我首先检查该行是否为数据行(这会排除分页符、标题行和页脚行)。然后,我获取构成 DIV 弹出菜单的控件的实例。首先,我获取 LinkButton 的实例,然后获取 DIV 标签的实例。请注意,我将 DIV 强制转换为 panel?这并非强制转换!由于 panel 是一个 DIV 标签,此方法有效,并且不会引发强制转换异常。如果您在 DIV 中有更多控件,请获取这些控件的实例以及 DIV 的实例。

现在我们已经获得了所需控件的实例,是时候调用客户端脚本函数了,但现在还不是时候。我将解释我尚未实现的内容。

还记得我写过您可以在 DIV 中拥有行特定菜单项吗?让我们稍微讨论一下。在 Row Data Bound 中,我们可以从绑定到 BoundField 或 TemplateField 的数据源中获取某个值,并基于此来控制 LinkButton 中控件的可见性。在我的示例中(请参阅新 GridView 的图像),我将 DIV 标签设置为最后一列的一部分,该列的名称为 STATUS。现在,我可以使用 STATUS 的单元格数据来显示 LinkButton。我所要做的就是在 if 语句中,检查 STATUS 的字符串值,并根据某个条件,我可以将 LinkButton 的客户端 ID 传递给脚本,或者,如果我不想显示 LinkButton,则可以传递一个 null 值而不是客户端 ID。当我向脚本传递 null 值时,脚本会根据此条件忽略该参数。

if(link1 != null) link1.style.display = "none";

这将确保脚本不会崩溃。现在,当您将鼠标悬停在每一行上时,您的 DIV 弹出菜单中都会有特定于菜单的项。由于我还将 e.Row 传递给了脚本,因此可以在 onmouseover 事件上更改整行的样式。这将使 GridView 看起来像是可点击的行。当然,您可以通过 JavaScript 添加样式来扩展它。

最后的润饰

我使用 JavaScript 设置了行背景和弹出 DIV 的背景。GIF 文件 td_mouseover.gif 只是一个渐变图像,在发生 onmouseover 事件时,它会为行提供一种浮雕效果。同样,文件 td_mouseover_inverted.gif 是 DIV 的渐变背景。

© . All rights reserved.