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

ASP.NET GridView Image Command Button 问题(多次回发)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.48/5 (16投票s)

2007年8月9日

Apache

3分钟阅读

viewsIcon

246618

downloadIcon

931

本文描述了在使用 ASP.NET GridView 中的 Image 类型命令按钮时(Internet Explorer 浏览器下)出现多次回发问题的解决方法。

最后更新:2008-10-10 更新了模板解决方案

要运行该应用程序,请将其下载并解压到计算机上的一个文件夹中,然后用 Visual Studio 2005(专业版或 Web 版)打开,并通过开发服务器运行。

Screenshot - Running.gif

引言

我遇到了一个问题:在 GridView 中通过点击 Type 为 Image 的 CommandField 来选择一行后,页面会加载两次。我发现客户端发送了两个请求:第一个请求不是我页面上的 PostBack 请求(这是我没想到的请求);第二个请求是我页面上的 PostBack 请求(这是我期望的请求)。

如果有什么非常奇怪的事情,我总是会用 FireFox 来检查,果然不出所料,只有一个请求(预期的 PostBack 请求)。因此,我也用 Internet Explorer 6 进行了检查,问题出现的概率大约是 4 次中有 1 次?!?

总结一下:

  • Internet Explorer 7:始终 2 个请求
  • Internet Explorer 6:有时正常,有时不正常
  • FireFox:一切正常

注意:这种行为仅在使用 CommandField 的 Type 为 Image 时出现,如果是 Link 或 Button 类型,一切都运行良好。

如果一切正常,我会如何处理?

以下 ASPX 定义显示了一个带有 Image 类型 CommandButton 的 GridView。

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 
    DataSourceID="ObjectDataSource1" 
    OnSelectedIndexChanged="SelectedIndexChanged">
    <Columns>
        <asp:CommandField ButtonType="Image" 
             SelectImageUrl="~/Select.gif" ShowSelectButton="True" />
        <asp:BoundField DataField="A" HeaderText="A" SortExpression="A" />
        <asp:BoundField DataField="B" HeaderText="B" SortExpression="B" />
        <asp:BoundField DataField="C" HeaderText="C" SortExpression="C" />
    </Columns>
</asp:GridView>  

这个 GridView 会导致我在引言中描述的问题。尽管我真的不明白哪里出了错,但它就是不起作用。如果您比较具有 Link 类型 CommandButton 的 GridView 和具有 Image 类型 CommandButton 的 GridView 所生成的 HTML,您会发现它们之间并没有太大区别——除了前者只有一个请求而后者有两个!

我花了一些时间在 Google 上搜索,发现了一些解决方法。我将找到的所有信息汇集起来,并在接下来的几节中向您展示三个解决方法,以及它们的优缺点。

解决方案 1 - 使用 Link 类型的 CommandButton,并将图像作为 HTML 添加到链接文本中

这是最简单的解决方法。我只是将 CommandButton 的类型从 Image 改为 Link,并将其 Text 属性设置为显示图像的 HTML。

<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" 
    DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:CommandField ShowSelectButton="True" 
            SelectText="<img src='Select.gif' border=0 title='This is a Tooltip'>">
        </asp:CommandField>
        <asp:BoundField DataField="A" HeaderText="A" SortExpression="A" />
        <asp:BoundField DataField="B" HeaderText="B" SortExpression="B" />
        <asp:BoundField DataField="C" HeaderText="C" SortExpression="C" />
    </Columns>
</asp:GridView>

这样做效果很好,但有一个缺点:工具提示文本的本地化变得困难。整个 HTML 字符串都必须添加到本地资源中,这不太方便。

解决方案 2 - 切换到 TemplateFields

为了获得更好的本地化解决方案,我删除了 CommandField 列,并添加了一个包含 ImageButton 的模板列。为了获得相同的行为,CommandName 必须设置为“Select”。

<asp:GridView ID="GridView3" runat="server" AutoGenerateColumns="False" 
    DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:TemplateField ShowHeader="false">
            <ItemStyle HorizontalAlign="Center" />
            <ItemTemplate>
                <asp:ImageButton ID="btnView" runat="server" 
                    CausesValidation="False" CommandName="Select"
                    ImageUrl="~/Select.gif" ToolTip="View" />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="A" HeaderText="A" SortExpression="A" />
        <asp:BoundField DataField="B" HeaderText="B" SortExpression="B" />
        <asp:BoundField DataField="C" HeaderText="C" SortExpression="C" />
    </Columns>
</asp:GridView>

自定义命令示例

为了让您的自定义命令正常工作,您可以选择使用 ButtonField,将其 ButtonType 设置为 Link,并使用与解决方案 1 中相同的技巧来显示图像,或者使用解决方案 2 中的模板字段。我更倾向于解决方案 2,但请确保在定义中包含 CommandArgument,否则您将无法访问行索引。

以下示例显示了这一点,以及不起作用的方法(请参阅工具提示以了解发生了什么)。

<asp:GridView ID="GridView4" runat="server" AutoGenerateColumns="False" 
              DataSourceID="ObjectDataSource1" OnRowCommand="RowCommand">
    <Columns>
        <asp:ButtonField ButtonType="Image" CommandName="MyCommand1" 
                         ImageUrl="~/Select.gif"
                         Text="Double PostBack in IE7 (sometimes in IE6)" />
        <asp:TemplateField ShowHeader="False">
            <ItemStyle HorizontalAlign="Center" />
            <ItemTemplate>
                <asp:ImageButton ID="btnView" runat="server" CausesValidation="False"
                                 CommandName="MyCommand2"
                                 CommandArgument="<%# Container.DataItemIndex %>"
                                 ImageUrl="~/Select.gif" 
                                 ToolTip="Works! Preferred solution." />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:ButtonField ButtonType="Link" CommandName="MyCommand3" 
            Text="<img src='Select.gif' border=0 title='Works! But bad localizable.'>"
        />
        <asp:BoundField DataField="A" HeaderText="A" SortExpression="A" />
        <asp:BoundField DataField="B" HeaderText="B" SortExpression="B" />
        <asp:BoundField DataField="C" HeaderText="C" SortExpression="C" />         
    </Columns>
</asp:GridView>

结论

Internet Explorer 中存在一个问题,在使用 Image 类型的 CommandButton 时会导致多次 PostBack。只要这个 bug 没有修复(或者每个人都使用 FireFox ;-)), 我们就必须使用一些解决方法。在本文中,我向您展示了三个解决方法以及您可以使用它们的场景。简而言之:如果您使用模板字段,您将始终是安全的。

如果您有更多信息、其他/更好的解决方法,甚至真正的解决方案,请在下方发布!

历史

  • 2007-08-09 初始版本
  • 2008-10-10 根据 Petr Behensky 在其消息帖子中的建议,更改了模板字段解决方案
© . All rights reserved.