GridView对动态列和数据源范围问题进行排序

时间:2011-08-05 19:50:50

标签: asp.net vb.net sorting gridview datatable

先读取 我重写了这篇文章,使其更具可读性。如果您想直接跳到追踪,请查看代码块中的所有CAPS注释。已包含所有必要的代码以进行调试。

我搜索了多个论坛(包括ASP.NET)和MSDN库,无法解决此问题>。<

目标:根据用户指定的列动态生成包含表格/网格的“状态报告”,其中包含最多20个(考虑因素:应该能够存储在用户首选项的cookie )。此网格将包含从SQL Server上的View提供的数据,并且行必须是可单击的。分页非常容易实现,但排序已被证明是一个令人讨厌的挑战。

问题(范围):我决定重新发布所有相关代码,以便更轻松地进行问题排查。

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    If Not IsPostBack Then
        chooseColumns()
    End If
End Sub

Protected Function queryToDataSet() As ArrayList
    'Code removed: Function returns the Columns to select from
End Function

'Handles the button click to build the `GridView` from the selected columns
Protected Sub ShowGrid(ByVal sender As Object, ByVal e As EventArgs) Handles btnSub.Click
    For Each item As ListItem In chkFields.Items
        If item.Selected Then
            Dim b As New BoundField()
            b.DataField = item.Value
            b.HeaderText = item.Value
            b.SortExpression = item.Value
            statusReportGrid.Columns.Add(b)
        End If
    Next
--> Me.GetData() 'HERE'S THE SCOPING ISSUE... UPON EXIT THE DATASOURCE IS LOST
End Sub

Private Sub GetData()
    statusReportGrid.DataSource = StatusDS
    statusReportGrid.DataBind()
End Sub

Protected Sub statusReportGrid_Sorting(ByVal sender As Object, ByVal e As GridViewSortEventArgs) Handles statusReportGrid.Sorting
    'CODE BREAKS HERE because the DataSource is no longer in scope
    Dim dataTable As DataTable = TryCast(statusReportGrid.DataSource, DataTable)
    If dataTable IsNot Nothing Then
        Dim dvSortedView As New DataView(dataTable)
        'The following line (when working properly) should return a string
        '  something like "StatusColumn DESC" for example. This format
        '  doesn't make sense to me and doesn't seem correct.
        dvSortedView.Sort = e.SortExpression + " " + getSortDirectionString(e.SortDirection)
        statusReportGrid.DataSource = dvSortedView
        statusReportGrid.DataBind()
    End If
End Sub

Private Function getSortDirectionString(ByVal sortDirection As SortDirection) As String
    Dim newSortDirection As String = String.Empty
    Select Case sortDirection
        Case sortDirection.Ascending
            newSortDirection = "ASC"
        Case sortDirection.Descending
            newSortDirection = "DESC"
    End Select
    Return newSortDirection
End Function

ASP控制 GridView控制(减去样式的东西) - 我读过的教程说将EnableViewState设置为false。当设置为true时,我会在刷新时重复列。

<asp:GridView ID="statusReportGrid" runat="server" AutoGenerateColumns="False" 
    AllowPaging="True" AllowSorting="True"
    EnableViewState="False" ShowHeaderWhenEmpty="True"></asp:GridView>

主要SqlDataSource控制状态报告内容。

<asp:SqlDataSource ID="StatusDS" runat="server" 
    ConnectionString="<%$ ConnectionStrings:StatusDBConnectionString %>"
    SelectCommand="SELECT * FROM [StatusTable]">
</asp:SqlDataSource>

问题 我刚刚发现这是一个范围问题,因为一旦我的调用函数导致DataSource绑定到我的GridView出口,DataSource就会变空。我当然感谢一些帮助解决我的范围问题,以便我的DataSource仍然可用并可由代码隐藏中的所有函数修改。只要页面显示得更多或更少,它就应该是持久的。

2 个答案:

答案 0 :(得分:1)

以下是使用DataTable&amp;背后的代码,在没有DataSource控件的情况下执行所需操作的示例。缓存以及管理视图状态中排序方向的自定义SortDirection函数。

''' <summary>
''' Show Grid
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Sub ShowGrid(sender As Object, e As EventArgs) Handles ShowGridButton.Click
    BuildGrid()
End Sub

''' <summary>
''' Sort GridView Columns
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Sub Sorting(ByVal sender As Object, ByVal e As GridViewSortEventArgs) Handles statusReportGrid.Sorting
    Dim dataTable As DataTable = BuildData()

    If DataTable IsNot Nothing Then
        Dim dvSortedView As New DataView(dataTable)

        dvSortedView.Sort = e.SortExpression + " " + getSortDirectionString()
        statusReportGrid.DataSource = dvSortedView
        statusReportGrid.DataBind()
    End If

End Sub

''' <summary>
''' Get and Store GridView SortDirection
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Private Function getSortDirectionString() As String
    Dim sortDirection As String = "ASC"

    If ViewState("GridSortDirection") IsNot Nothing Then
        If ViewState("GridSortDirection").ToString() = "ASC" Then
            sortDirection = "DESC"
        Else
            sortDirection = "ASC"
        End If
    End If

    ViewState("GridSortDirection") = sortDirection

    Return sortDirection
End Function

''' <summary>
''' Build Dynamic GridView Columns
''' </summary>
''' <remarks></remarks>
Protected Sub BuildGrid()
    Dim dataTable As New DataTable
    dataTable = BuildData()

    If dataTable.Rows.Count > 0 Then
        For Each item As ListItem In chkFields.Items
            If item.Selected Then
                Dim b As New BoundField()
                b.DataField = item.Value
                b.HeaderText = item.Value
                b.SortExpression = item.Value
                statusReportGrid.Columns.Add(b)
            End If
        Next

        statusReportGrid.DataSource = dataTable
        statusReportGrid.DataBind()
    End If
End Sub

''' <summary>
''' Get DataTable from DB and Use Cache to Store 
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Protected Function BuildData() As DataTable
    Dim dataTable As New DataTable

    If Cache("StatusDBResults") IsNot Nothing Then
        dataTable = TryCast(Cache("StatusDBResults"), DataTable)
        Return dataTable
    End If

    Dim queryString As String
    queryString = "SELECT * FROM [StatusTable]"

    Using connection As New SqlConnection(ConfigurationManager.ConnectionStrings("StatusDBConnectionString").ConnectionString)
        Dim adapter As New SqlDataAdapter()
        adapter.SelectCommand = New SqlCommand(queryString, connection)
        adapter.Fill(dataTable)

        'Add To Cache for 2 Minutes for Sorting/Paging/Downloading
        Cache.Add("StatusDBResults", dataTable, Nothing, System.Web.Caching.Cache.NoAbsoluteExpiration, New TimeSpan(0, 2, 0), System.Web.Caching.CacheItemPriority.Default, Nothing)

        'MY CODE - Gets the Column Names and dumps them into the ASP.NET CheckBoxList control
        'There may be a better way to do this using the DataTable, but I wasn't able to get that to work. This works and it's pretty fast.
        connection.Open()
        Dim colQuery As New SqlCommand("select column_name from information_schema.columns where table_name = 'StatusTable'", connection)
        Dim dr As SqlDataReader = colQuery.ExecuteReader
        Dim colsArr As New ArrayList
        While dr.Read
            colsArr.Add(dr.Item(0))
        End While
        chkFields.DataSource = colsArr
        chkFields.DataBind()

        Return dataTable
    End Using
End Function

以下是我用于测试的示例HTML控件源....

<asp:GridView runat="server" AutoGenerateColumns="False" AllowPaging="True" AllowSorting="True" ID="statusReportGrid">
</asp:GridView>
<asp:CheckBoxList runat="server" ID="chkFields" RepeatDirection="Horizontal" RepeatLayout="Flow" />
<asp:Button runat="server" Text="Button" ID="ShowGridButton" />

如果这有意义,请告诉我,我通常不会在VB中编码。 SortDirection是一个已知问题,因为它总是返回Ascending。至于DataTable vs SqlDataSource的使用,两者都可以使用,但我发现DataTable方法更容易。

答案 1 :(得分:0)

由于您将DataSource设置为新的DataView,因此当您再次返回时,您将不再拥有DataTable - 只需DataView。因此,您的TryCast将无效。

我不知道为什么IsNot Nothing成功了。