PsychoDUCK
PsychoDUCK

Reputation: 1103

asp.net ListView Sorting using DataBind

Sort listview using column headings in the LayoutTemplate

I am able to sort a basic list view using asp:SqlDataSource and setting the list view property DataSourceID by pointing it to the asp:SqlDataSource ID. I am having an issue when sorting when not using the asp:SqlDataSource and just DataBinding from the code behind.

SqlDataSource Example:

<asp:ListView ID="ContactsListView" DataSourceID="ContactsDataSource" runat="server">
    <LayoutTemplate>
        <table width="640px" runat="server">
            <tr class="header" align="center" runat="server">
                <td>
                    <asp:LinkButton runat="server" ID="SortByFirstNameButton" CommandName="Sort" Text="First Name" CommandArgument="FirstName" />
    </LayoutTemplate>
    ....
</asp:ListView>

<asp:SqlDataSource ID="ContactsDataSource" runat="server" 
    ConnectionString="<%$ ConnectionStrings:MainConnString %>"
    SelectCommand="SELECT * FROM TableName">
</asp:SqlDataSource>

DataBind Example:

<asp:ListView ID="ContactsListView" DataSourceID="ContactsDataSource" runat="server">
    <LayoutTemplate>
        <table width="640px" runat="server">
            <tr class="header" align="center" runat="server">
                <td>
                    <asp:LinkButton runat="server" ID="SortByFirstNameButton" CommandName="Sort" Text="First Name" CommandArgument="FirstName" />
    </LayoutTemplate>
    ....
</asp:ListView>

protected void Page_Load(object sender, EventArgs e)
{
    String SQL = "SELECT * FROM Customer";
    SqlDataAdapter da= new SqlDataAdapter(SQL, ConnStr);
    DataSet ds = new DataSet();
    da.Fill(ds);

    ContactsListView.DataSource = ds.Tables[0];
    ContactsListView.DataBind();
}

Both code samples populate the list view, but the second example data binding does not work for sorting. With the first example, the sorting just works with the added asp:LinkButton in the LayoutTemplate adding the CommandName="sort" and setting the CommandArugment="ColumnName", but it does not work with the second example.

Can anyone please explain why and how to get the sorting working using the code behind DataBind method?

Thanks!

Upvotes: 2

Views: 17593

Answers (3)

PsychoDUCK
PsychoDUCK

Reputation: 1103

I solved my issue.

I added an event to handle the sorting. The event grabs the command name (Data column) and passes it and the sorting direction into a function which will make another call to the database sort the returned results and rebind to the List View.

I had to create a view state to hold the List View Sort Direction because for some reason, the onsorting event handler kept saying that the sort direction was ascending.

Front End

<asp:ListView ID="ContactsListView" OnSorting="ContactsListView_Sorting" runat="server">
    <LayoutTemplate>
        <table width="640px" runat="server">
            <tr class="header" align="center" runat="server">
                <td>
                    <asp:LinkButton runat="server" ID="SortByFirstNameButton" CommandName="Sort" Text="First Name" CommandArgument="FirstName" />
    </LayoutTemplate>
    ....
</asp:ListView>

Back End

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        BindContacts(string.Empty);
    }
}

protected SortDirection ListViewSortDirection
{
    get
    {
        if (ViewState["sortDirection"] == null)
            ViewState["sortDirection"] = SortDirection.Ascending;
        return (SortDirection)ViewState["sortDirection"];
    }
    set { ViewState["sortDirection"] = value; }
}

protected void ContactsListView_Sorting(Object sender, ListViewSortEventArgs e)
{
    BindContacts(e.SortExpression + " " + ListViewSortDirection.ToString());

    // Check the sort direction to set the image URL accordingly.
    string imgUrl;
    if (ListViewSortDirection == SortDirection.Ascending)
        ListViewSortDirection = SortDirection.Descending;
    else
        ListViewSortDirection = SortDirection.Ascending;
}

private void BindContacts(string sortExpression)
{
    sortExpression = sortExpression.Replace("Ascending", "ASC");
    sortExpression = sortExpression.Replace("Descending", "DESC");
    using (SqlConnection conn = new SqlConnection(_connStr))
    {
        conn.Open();
        using (SqlDataAdapter dAd = new SqlDataAdapter("SELECT * FROM Customer", conn))
        {
            DataTable dTable = new DataTable();
            dAd.Fill(dTable);
            // Sort now
            dTable.DefaultView.Sort = sortExpression;
            // Bind data now
            ContactsListView.DataSource = dTable;
            ContactsListView.DataBind();
        }
        conn.Close();
    }
}

Upvotes: 9

Icarus
Icarus

Reputation: 63956

Because depending on the sort expression (which you defined in your markup) SqlDataSource will very likely do something like this (I'm not sure this is exactly what it does) for you behind the scenes:

Expression<Func<DataRow,object>> myExpression = row => row["SortExpressionYouDefinedForTheColumn"];
IEnumerable<DataRow> ex = ds.Tables[0].AsEnumerable().OrderBy(myExpression.Compile());

Or SqlDataSource may be using a DataView to sort the DataTable.

SqlDataSource can do this because by default it uses a DataSet to store the result set (or so says the documentation):

The data retrieval mode identifies how a SqlDataSource control retrieves data from the underlying database.

When the DataSourceMode property is set to the DataSet value, data is loaded into a DataSet object and stored in memory on the server. This enables scenarios where user interface controls, such as GridView, offer sorting, filtering, and paging capabilities..

Since you chose to bind manually to a DataSet, you need to do the "magic" yourself; in other words, you handle the OnSort command, get the sort expression, get your data source again (however you do it, from Session or by calling the database again) and do your sort similarly to the lines shown above and rebind to your Gridview.

Upvotes: 0

Wiktor Zychla
Wiktor Zychla

Reputation: 48230

I guess you could try to add a handler for ListView's Sorting event. There you are given the sorting column and the sort order in the event arguments. This could be easily usable to build a specific query and bind it to the list.

Upvotes: 0

Related Questions