如何使用 Eval 处理空值

How to handle nulls with Eval

我可以有一条记录,其中所有字段都已填写,但没有 SO_ID 或 SO_Num。我希望我的 eval 能够处理这些,并且在发生这种情况时只 return 网格列中的“-”,同时仍然 returning 该行的所有其他数据。我在网上尝试了其他解决方案,但找不到有效的解决方案。

<dx:GridViewDataColumn FieldName="SO_Num" VisibleIndex="19" runat="server" Caption="Sales Order Number">
<DataItemTemplate>
 <a id="clickElement" href="../sales/order/view.aspx?ID=<%# Eval("SO_ID").ToString()%>"><%#Eval("SO_Num").ToString()%></a>
 </DataItemTemplate>
</dx:GridViewDataColumn> 

您可以使用 in-line "iif(),因此:

                <asp:TemplateField HeaderText="City">
                    <ItemTemplate>
                        <asp:TextBox ID="txtCity" runat="server" 
                            Text = '<%# IIf(IsDBNull(Eval("City")), "-", Eval("City")) %>'
                            ></asp:TextBox>
                    </ItemTemplate>
                </asp:TemplateField>

所以,在上面,如果说 Eval("City") 为空,那么我们显示一个“-”,否则我们显示 Eval("City")

编辑:值的显示和一些点击和导航的按钮是不同的!!

正如我所指出的,如果您需要在 GridView 中使用 Eval(),并且想将 null say 转换为“-”,那么就这样做吧(但是,我不明白为什么要显示GV 中有一些“-”。为什么要这样做??我觉得很奇怪?

但是,如果您在 GV 行上有一个按钮,并且您想要单击该按钮跳转或导航到其他页面?看不出这样的按钮点击和导航与我们显示的内容有什么关系?这两个概念为什么联系在一起?我在这里看不到任何合理的逻辑?

如果你想放入一个 pane jane 按钮,甚至是一个 link 按钮(这里没有区别),然后为你放入的给定按钮连接一个点击事件。

所以,比如说在我们的 GV 中,我们放入一个按钮来查看给定的数据行。用酒店和按钮说这个 GV。

        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
            CssClass="table table-hover" Width="50%"
            DataKeyNames="ID" >
            <Columns>
                <asp:BoundField DataField="FirstName" HeaderText="FirstName"  />
                <asp:BoundField DataField="LastName" HeaderText="LastName" />
                <asp:TemplateField HeaderText="Hotel Name">
                    <ItemTemplate>
                        <asp:Label ID="txtHotel" runat="server"
                            Text='<%# Eval("HotelName") %>' >
                        </asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:BoundField DataField="Description" HeaderText="Description" />

                <asp:TemplateField HeaderText="View">
                    <ItemTemplate>
                    <asp:Button ID="cmdView" runat="server"  Text="View" CssClass="btn "
                      />
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
            <PagerStyle CssClass="pagenavi" />
        </asp:GridView>

所以,我们只是放入了一个平面简按钮,用于对该行进行操作。

所以,我们要加载的代码是这样的:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    If Not IsPostBack Then
        LoadGrid()
    End If

End Sub

Sub LoadGrid()

    Using conn As New SqlConnection(My.Settings.TEST4)
        Dim strSQL As String =
            "SELECT * from tblHotelsA ORDER BY HotelName"
        Using cmdSQL As New SqlCommand(strSQL, conn)
            conn.Open()
            Dim rst As New DataTable
            rst.Load(cmdSQL.ExecuteReader)
            GridView1.DataSource = rst
            GridView1.DataBind()
        End Using
    End Using

End Sub

现在我们的结果是这样的:

好的,现在让我们连接飞机简按钮点击。

作为正常规则,您可以双击按钮来构建点击事件,或者调出 属性 sheet,选择事件 tab/section,然后添加点击事件。但是,由于按钮在 GV 中,因此我们必须以这种方式(在标记中)添加点击事件。

键入 OnClick=,当您点击“=”符号时,intel-sense 将弹出一个对话框以创建事件。

你明白了:

因此,我们 select 创建新事件。看起来什么都没有发生,但是转到后面的代码,我们有一个点击事件存根,因此我们的代码可以是这样的:

Protected Sub cmdView_Click(sender As Object, e As EventArgs)

    Dim btn As Button = sender
    Dim gRow As GridViewRow = btn.Parent.Parent
    Dim intPKID As Integer = GridView1.DataKeys(gRow.RowIndex).Item("ID")

    Debug.Print("Row click index = " & gRow.RowIndex)
    Debug.Print("Row click database PK id = " & intPKID)

    ' now do whatever you want with this row information.

    ' to get values from non templated columns, use cells()
    ' to get values from tempated columns, use findcontrol

    'eg:

    ' get last name (Boundfield)

    Debug.Print("Last name = " & gRow.Cells(1).Text)

    ' get hotel name - template - "label"

    Dim lblHotel As Label = gRow.FindControl("txtHotel")

    Debug.Print("Hotel name (label) = " & lblHotel.Text)


End Sub

输出:

所以,如前所述,我不明白为什么这里会出现关于 GV 列中某些数据为空的任何问题?

在您的情况下,只需根据按钮点击导航到您想要的任何内容,根据您想要的任何值。

这样说:

然后在后面的代码中:

Protected Sub cmdView_Click(sender As Object, e As EventArgs)

    Dim btn As Button = sender
    Dim gRow As GridViewRow = btn.Parent.Parent
    Dim intPKID As Integer = GridView1.DataKeys(gRow.RowIndex).Item("ID")

    Debug.Print("Row click index = " & gRow.RowIndex)
    Debug.Print("Row click database PK id = " & intPKID)

    Dim intSOID = btn.CommandArgument

    Dim strURLJumpTo = "../sales/order/view.aspx?ID=" & intSOID

    Response.Redirect(strURLJumpTo)

因此,您可以随意编造您想要的任何 URL 导航。

注意非常接近我如何使用 GV 的数据密钥功能。这让我可以拥有、使用、获取、玩弄数据库 PK 行 ID,但我永远不必在实际 GV 标记中公开、显示、拥有或弄乱数据库 PK id。

这不仅很好,而且从安全的角度来看也是一笔巨大的交易,从那时起,用户、浏览器(客户端)就永远不必看到、知道或可以修改或玩数据库 PK 行 ID - 它是 100% 服务器端管理的。

事实上,如果您 SO_ID 或任何值不在 GV 中,或者用户不关心?然后我不会将 URL 中的值作为 URL 的所谓“查询参数”传递,但实际上会像这样传递 session() 中的值:

    Session("OrderID") = intPKID



    Response.Redirect("../sales/order/view.aspx")

然后在目标页面的页面加载事件中,我这样做:

永远不要忘记 check/use 页面加载事件中的 ispostback。

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    If Not IsPostBack Then

        ViewState("OrderID") = Session("OrderID")

现在,在后面的代码和那个页面中,您使用它来 get/use/have orederid

 dim intOrderID = ViewState("OrderID")

因此,在页面加载时(第一页,ispostback = false),您将 session() 值传输到 ViewState。你这样做是因为用户可能拥有多个浏览器副本 运行 - 因此使用 session() 传递值是可以的,但是 session() 对一个用户来说是全局的,而 ViewState 是每页。所以,这就是我们在页面加载时转移到 ViewState 的原因,因为从该点开始,在该页面和后面的代码中,我们使用 ViewState。如果我们在后面的代码中使用session(),那么它是全局的,如果浏览器的多个副本是运行甚至多个表,它们将具有相同的session()值。

那么,假设您点击要查看或购买的房子?

好吧,那么他们可能会打开另一个选项卡 - 显示相同的 GV,然后单击不同的行。如果我们使用会话,您现在显示两个页面 - 但它们都有同一行 PK id 值 - 如果您单击购买房子,如果您的代码后面使用 session(),您会得到错误的房子,但使用 ViewState,问题不存在。

因此,您甚至可以从 URL 中转储您的 ugle“id”和参数 - 它们看起来更好,但也更安全,因此用户不必看到,或知道一个t之类的数据库行PK垃圾什么的