Here was the issue:
When the LinkButton is clicked, the first thing that happens is the page reloads. However, Response.Redirect(Request.RawUrl)
doesn’t preserve the ViewState, so the sort order is lost. Therefore, the GridView is repopulated with unsorted data.
Then, the LinkButton onClick event function is called. The Object passed in is the LinkButton from the correct row number, but since the sort order of the table had changed (back to its unsorted state), the LinkButton in that row was no longer the LinkButton the user had clicked. Therefore, the command argument was wrong.
To fix the issue:
I changed all the ViewState[string] to Session[string] (so that the sort direction is preserved when the page reloads), and added the following code in the Page_Load function, before the GridView is bound:
if (Session["companiesExpression"] != null
&& Session["companiesDirection"] != null)
{
companies.DefaultView.Sort = Session["companiesExpression"] + " " +
Session["companiesDirection"];
}