Sort not firing PostBack event using Dynamic Columns

T

tsarna

I am having a problem with the DataGrid control and sorting, and have found it's realted to if you use dynamic columns or not. If I set the columns up on the aspx page and not in the code behind dynamically, the SortEvent will fire without requiring a double bind to the DataGrid. Below is code that will recreate the problem... If you comment out the ' If Not IsPostBack Then', and have it bind on every postback the event fires.

I would prefer to not have to perfrom a double databind so any help on this is appreciated!!!

Thanks
-Tim Sarna

..ASPX Page
------------------------------------------
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="Dynamic.aspx.vb" Inherits="TestWeb.Dynamic" %>

<HTML>
<body>
<form runat="server" ID="Form1">

<h3>DataGrid Paging/Sorting - Dynamic Columns</h3>

<asp:DataGrid id="DataGrid1" runat="server" BorderColor="black"
AllowPaging="true" AutoGenerateColumns="false" AllowSorting="True">
<HeaderStyle BackColor="#00aaaa"></HeaderStyle>
<PagerStyle Mode="NextPrev"></PagerStyle>
</asp:DataGrid>
</form>
</body>
</HTML>

'Code Behind
'------------------------------
Public Class Dynamic
Inherits System.Web.UI.Page

#Region " Web Form Designer Generated Code "

'This call is required by the Web Form Designer.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

End Sub
Protected WithEvents DataGrid1 As System.Web.UI.WebControls.DataGrid

'NOTE: The following placeholder declaration is required by the Web Form Designer.
'Do not delete or move it.
Private designerPlaceholderDeclaration As System.Object

Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
'CODEGEN: This method call is required by the Web Form Designer
'Do not modify it using the code editor.
InitializeComponent()
End Sub

#End Region

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
If Not IsPostBack Then
' Need to load this data only once.
CreateGridColumns()
DataGrid1.DataSource = CreateDataSource()
DataGrid1.DataBind()
End If
End Sub 'Page_Load

Private Sub Sort_Change(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
' Rebind the data.
CreateGridColumns()
DataGrid1.DataSource = CreateDataSource(e.SortExpression)
DataGrid1.DataBind()
End Sub

Sub Page_Change(ByVal sender As Object, ByVal e As DataGridPageChangedEventArgs) Handles DataGrid1.PageIndexChanged
' Set CurrentPageIndex to the page the user clicked.
DataGrid1.CurrentPageIndex = e.NewPageIndex

' Rebind the data.
CreateGridColumns()
DataGrid1.DataSource = CreateDataSource()
DataGrid1.DataBind()
End Sub 'Grid_Change


Public Function CreateDataSource(Optional ByVal SortColumn As String = "IntegerValue") As ICollection
Dim dt As New DataTable
Dim dr As DataRow

dt.Columns.Add(New DataColumn("IntegerValue", GetType(Int32)))
dt.Columns.Add(New DataColumn("StringValue", GetType(String)))
dt.Columns.Add(New DataColumn("CurrencyValue", GetType(Double)))

Dim i As Integer
For i = 0 To 99
dr = dt.NewRow()
dr(0) = i
dr(1) = "Item " + i.ToString()
dr(2) = 1.23 * (i + 1)
dt.Rows.Add(dr)
Next i

Dim dv As New DataView(dt)
dv.Sort = SortColumn
Return dv
End Function 'CreateDataSource

Public Sub CreateGridColumns()

Me.DataGrid1.Columns.Clear()

Dim col As New BoundColumn

col = New BoundColumn
Me.DataGrid1.Columns.Add(col)
col.HeaderText = "Number"
col.DataField = "IntegerValue"
col.SortExpression = "IntegerValue"

col = New BoundColumn
Me.DataGrid1.Columns.Add(col)
col.HeaderText = "Item"
col.DataField = "StringValue"
col.SortExpression = "StringValue"

col = New BoundColumn
Me.DataGrid1.Columns.Add(col)
col.HeaderText = "Price"
col.DataField = "CurrencyValue"
col.SortExpression = "CurrencyValue"
col.DataFormatString = "{0:c}"

End Sub
End Class
 
S

Scott M.

The problem is that you have AutoGenerateColumns = False and so the Grid
doesn't know when it's own sort command or pageindexchanged (or any other
event) has fired. I set the grid to "Create Columns Automatically At Run
Time" and changed your code to not only make it work, but make it more
efficient. The "CreateGridColumns()" routine is no longer needed. The
following works for me:

****************************************************************************

Public Class WebForm2
Inherits System.Web.UI.Page

Dim dt As DataTable

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
If Not IsPostBack Then
DataGrid1.DataSource = CreateDataSource()
DataGrid1.DataBind()
Else
'Fetch the DataTable from the cache and use it as the datasource this
time instead of re-creating the data
dt = CType(Cache.Item("dataTbl"), DataTable)
DataGrid1.DataSource = dt
End If
End Sub

Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As
System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles
DataGrid1.SortCommand
' Rebind the data.
Dim dv As New DataView(dt)
dv.Sort = e.SortExpression
DataGrid1.DataSource = dv
DataGrid1.DataBind()
End Sub

Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As
System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles
DataGrid1.PageIndexChanged
' Set CurrentPageIndex to the page the user clicked.
DataGrid1.CurrentPageIndex = e.NewPageIndex

' Rebind the data.
DataGrid1.DataBind()
End Sub

Public Function CreateDataSource() As DataTable
'Populate a DataTable and return it so it can be used as the datagrid's
datasource
dt = New DataTable
dt.Columns.Add(New DataColumn("Number", GetType(Int32)))
dt.Columns.Add(New DataColumn("Item", GetType(String)))
dt.Columns.Add(New DataColumn("Price", GetType(Decimal)))

Dim i As Integer, dr As DataRow
For i = 0 To 99
dr = dt.NewRow()
dr(0) = i
dr(1) = "Item " & i.ToString()
dr(2) = 1.23 * (i + 1)
dt.Rows.Add(dr)
Next

'Store the resulting populated DataTable in the cache so we don't
' have to re-create it each time the page loads
Cache.Insert("dataTbl", dt)

Return dt
End Function
End Class
 
T

tsarna

Thanks for the response.

The example I gave was just to show where the problem was, and to show that the sort command doesn’t fire when using dynamic columns (which we need to use). I am actually able to get sorting and paging to work when I store the dataset in viewstate or cache, use AutoGeneratedColumns=True, and also if I hard code the columns on the aspx page.

The problem I have is that I can’t store the entire dataset in viewstate (because of the size) or in cache/session (because our load balanced environment doesn’t allow us to store session – long story). With this, we are forced on paging and sorting to retrieve the data each time one of these two events occurs. What’s interesting, is that paging will fire without requiring a databind in the Page_Load, but sorting requires that we re-bind to the dataset in Page_Load and then again in the SortCommand (a double hit to the database)

I have found a work around, by storing (cloning) only the schema information of the dataset in viewstate, and then rebinding to it in the Page_Load, and then letting the sort do a full dataset reload with the new criteria in the SortCommand method. It’s not a perfect fix, but it does reduce the amount of data stored in ViewState.

Thanks again!
Tim Sarna
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,034
Messages
2,570,356
Members
47,002
Latest member
RobertoLip

Latest Threads

Top