Search code examples
c#asp.netlistviewsortingcode-behind

Listview sort code apparently interfering with item processing code


Running VWD 2010 Express on a windows 7 machine.

I have a asp:listview (on a tab) that has column headers that sort the data (with no code on my part). This part works when it is by itself. But it fails when I try to then put in code to support the items in the list. So here is what I have so far:

(1) I can sort the items in a listview by clicking on a header ("title" in this case) asp:ListView provides a mechanism for sorting the list by clicking on the title without using code behind. We can do this with a button like so:

<asp:Button runat="server" ID="SortTitle" Text="Title" CommandName="Sort"  CommandArgument="sTitle"   />

No code behind. This title is in the header which is outside the item template. It works fine. I can sort lists ascending and descending to my heart's content by clicking on the associated header. This is good, but I also would like to have the program "do something" when an item in the list is clicked.

(2) I can make something happen when I click on an item in the list. Fortunately, there is a mechanism for controlling what happens when an item is clicked in the list via the OnItemCommand attribute in the asp:ListView tag.

<asp:ListView runat="server" ID="lvWebsites" DataSourceID="websiteSuggestionsDataSource" OnItemCommand="lv_website_click"  >

This works kinda so-so. It does what I want, but it reloads the page (which I don't want to do). It's a separate issue and I may open a different question on that. The main thing is that I can click on the item in the list and it executes some code behind.

The real problem comes in when I use (1) and (2) together. When I do that, it ignores the CommandName="Sort" in the button tag and executes the code behind (lv_website_click) regardless of whether I click on the header (title) or an actual item in the list. It's as if the system makes no distinction between a header in a listview and an actual list item in the listview.

Here's a subset of the actual code I'm using. I'm using tabs and this particular listview is on the first tab so I include that...the entire code is a fair bit longer, but I think you can get the general context with this (and most of the rest is repeats of this code).

<div id='tab-container'>

    <div class="tab-content" style="width:1000px">
            <h1 class="tab" title="Feedback on the site">Site Feedback</h1>
            <asp:ListView runat="server" ID="anID"
                DataSourceID="mydatasource"
                OnItemCommand="lv_website_click"  >

                <LayoutTemplate>
                <table    id="table1" style="background-color:White;border-collapse:collapse;" width="100%">
                    <tr style="background-color:White">
                        <td  width="75%">
                        <asp:Button runat="server" ID="SortTitle" 
                          Text="Title" CommandName="Sort"  CommandArgument="sTitle"   /></td>
                        <td>    <asp:Button runat="server" ID="LinkButton1" 
                          Text="Posted" CommandName="Sort" CommandArgument="sDate"   /></td>
                        <td>     <asp:Button runat="server" ID="SortDate" 
                          Text="Status" CommandName="Sort" CommandArgument="sStatus" /></td>
                    </tr>
                    <tr runat="server" id="itemPlaceholder">
                    </tr> 
                </table>
                <asp:DataPager runat="server" ID="datapagerSites" PageSize="10" style="background-color:White" enableviewstate="false"
                PagedControlID="lvWebsites"  >
                    <Fields>
                      <asp:TemplatePagerField>              
                        <PagerTemplate>
                        <b>
                        Page
                        <asp:Label runat="server" ID="CurrentPageLabel" 
                          Text="<%# Container.TotalRowCount>0 ? (Container.StartRowIndex / Container.PageSize) + 1 : 0 %>" />
                        of
                        <asp:Label runat="server" ID="TotalPagesLabel" 
                          Text="<%# Math.Ceiling ((double)Container.TotalRowCount / Container.PageSize) %>" />
                        (
                        <asp:Label runat="server" ID="TotalItemsLabel" 
                          Text="<%# Container.TotalRowCount%>" />
                        records)
                        <br />
                        </b>
                        </PagerTemplate>
                      </asp:TemplatePagerField>

                      <asp:NextPreviousPagerField
                        ButtonType="Button"
                        ShowFirstPageButton="true"
                        ShowNextPageButton="false"
                        ShowPreviousPageButton="false" />

                      <asp:NumericPagerField 
                        PreviousPageText="&lt; Prev 10"
                        NextPageText="Next 10 &gt;"
                        ButtonCount="10" />

                      <asp:NextPreviousPagerField
                        ButtonType="Button"
                        ShowLastPageButton="true"
                        ShowNextPageButton="false"
                        ShowPreviousPageButton="false" />


                    </Fields>
                </asp:DataPager>
                </LayoutTemplate>
                <ItemTemplate>
                <tr id="Tr1" runat="server" style="background-color:#ECE5B6;" >
                    <td><asp:Button  BackColor="#ECE5B6" CommandName="lcommand" runat="server" ID="Title"   Text='<%# Eval("sTitle")%>'   CommandArgument='<%# Eval("sID") %>' /></td>
                    <td><asp:Label runat="server" ID="Label1"  Text='<%# Eval("posted")%>'  /></td>
                    <td><asp:Label runat="server" ID="Status"  Text='<%# Eval("sStatus")%>' /></td>
                </tr>
                </ItemTemplate>
                <AlternatingItemTemplate>
                <tr id="Tr1" runat="server" style="background-color:#FAF8CC;" >
                    <td><asp:Button BackColor="#FAF8CC" CommandName="lcommand" runat="server" ID="Title"   Text='<%# Eval("sTitle")%>'  CommandArgument='<%# Eval("sID") %>' /></td>
                    <td><asp:Label runat="server" ID="Label1"  Text='<%# Eval("posted")%>'  /></td>
                    <td><asp:Label runat="server" ID="Status"  Text='<%# Eval("sStatus")%>' /></td>
                </tr>

                </AlternatingItemTemplate>
            </asp:ListView>
    </div>
</div>

It strikes me I could maybe do both things in my own code to handle the items, but I really don't like that as I would like to use the automatic sorting behavior I get from the Listview control.

I would think OnItemCommand="lv_website_click" in asp:listview tag would apply to the items and the CommandName="Sort" CommandArgument="sTitle" would apply to the headers (used for sorting) because they are outside the itemtemplate. Apparently that is not true.

IS there a way to use both of these (sorting with a click on header AND code behind for items in the list) so they do not conflict with each other?


Solution

  • The solution is in the code-behind.

    protected void lv_website_click(object sender, ListViewCommandEventArgs e) { if (!e.CommandName.Equals("Sort")) { int searchID = Convert.ToInt32(e.CommandArgument.ToString());

        TableAdapters.SuggestionsTableAdapter sAdapt =
            new TableAdapters.SuggestionsTableAdapter();
    
        SuggestionsDataTable tbl = sAdapt.GetDataByID(searchID);
    
        tbMessage.Text = tbl.Rows[0]["message"].ToString();
        lbField2.Text = tbl.Rows[0]["field2"].ToString();
        lbStuff.Text = tbl.Rows[0]["stuff"].ToString();
    
        }
    }
    

    The key is the "if" surrounding the body of the method. If it's not a sort event (i.e. the CommandName is not equal to "Sort" then do whatever it is you're supposed to do when you click on an item. OTHERWISE, if it is a sort, just ignore the code. I misunderstood what was happening here. I thought it was ignoring the sort and executing the other code regardless. What was happening is that if the CommandName is Sort, then it is doing the sort, but it is also executing my behind code (which is where it was having the error).

    That is, it was not a problem with the aspx (as I had thought), but with the c# behind.