I have similiar problem just that my gridview only sorts in the ascending order for the particular column. I have done a few debugging and tracing and found out that the gridview somehow 'forgets' its current SortExpression.
Step 0 : No column is being sorted yet. Therefore the SortExpression of the gridview will return an empty string. The SortDirection of the gridview will return 'Ascending'.
Step 1 : I click on a column header to initiate a sort for that column. Since this is the first time I click on the column header, the column should be sorted in the ascending order. The expected SortExpression of the gridview now should be the column name and the SortDirection should be 'Ascending'
Step 2 : Yes, the column is being sorted in the ascending order as expected. However, as soon as the column is being sorted, the SortExpression of the gridview is resetted to an empty string and the SortDirection is 'Ascending'.
Step 3 : I click on the same column header again which now should be sorted in the descending order. However, since the SortExpression has been resetted to an empty string in Step 2, the column will be sorted in the ascending order again as if this is the first time I click on the column header.
Then the steps repeat all over again.
I only face this problem when I'm using the gridview in conjunction with a master page. I do not have this problem when I'm using it on normal web pages without a master page.
Here is what I know and suspcect. When I checked the HTML codes that is returned from the webserver,
the id of my gridview has been changed to MasterPageID_ContentPlaceHolderID_myGridViewID.
If I din assign my master page an ID, then it will generate a 'ctl00' as the id for the master page.
If I assign 'title' and 'gvItems' as the id of my contentplaceholder and gridview respectively, then the HTML id that I will get is 'ctl00_title_gvItems'.
ASP .NET will generate Unique client ID for the controls on the webpage which has 'runat="server"' as their attribute. If the control is nested in another control, then ASP .NET will create an ID preceded with the id of the parents of the controls delimited with an underscore. For example parentID1_parentID2_ControlID. In this example ControlID is nested within parentID2 which in turn is nested within parentID1.
The above is how ASP.NET create an 'id' for controls. ASP .NET adopts the same naming convention in creating a 'name' for a control just that the delimiter is a dollar sign instead of an underscore. For example of the above case, the name of the control would be parentID1$parentID2$ControlID.
For web server controls like gridview, ASP .NET will only generate an id for it. There won't be any name for that control.
When I hover over a column header, I got the link location something like 'javascript:__doPostBack('ctl00$title$gvItems','Sort$CreateDate')'
We can clearly see that the first argument of the function doPostBack is the 'name' of my gridview. But my gridview does not have a name attribute. It only has an id attribute which is 'ctl00_title_gvItems'. I think here is where everything gone wrong.