Albert D. Kallal
Albert D. Kallal

Reputation: 49169

Highlight ListView row without re-bind or apply style to that row

Typical listview.

    <asp:ListView ID="ListView1" runat="server" DataKeyNames="ID" OnSelectedIndexChanging="ListView1_SelectedIndexChanging" 
        OnSelectedIndexChanged="ListView1_SelectedIndexChanged">
        <ItemTemplate>
            <tr style="">
                <td>
                    <asp:Label ID="FirstNameLabel" runat="server" Text='<%# Eval("FirstName") %>' />
                </td>
                <td>
                    <asp:Label ID="LastNameLabel" runat="server" Text='<%# Eval("LastName") %>' />
                </td>
                <td>
                    <asp:Label ID="HotelNameLabel" runat="server" Text='<%# Eval("HotelName") %>' />
                </td>
                <td>
                    <asp:Label ID="CityLabel" runat="server" Text='<%# Eval("City") %>' />
                </td>
                <td>
                    <asp:Button ID="cmdLstSel" runat="server" Text="View" CssClass="btn" 
                        CommandName="Select"/>
                </td>
            </tr>
        </ItemTemplate>
        <SelectedItemTemplate>
            <tr style="" class="alert-info">
                <td>
                    <asp:Label ID="FirstNameLabel" runat="server" Text='<%# Eval("FirstName") %>' />
                </td>
                <td>
                    <asp:Label ID="LastNameLabel" runat="server" Text='<%# Eval("LastName") %>' />
                </td>
                <td>
                    <asp:Label ID="HotelNameLabel" runat="server" Text='<%# Eval("HotelName") %>' />
                </td>
                <td>
                    <asp:Label ID="CityLabel" runat="server" Text='<%# Eval("City") %>' />
                </td>
                <td>
                    <asp:Button ID="cmdLstSel" runat="server" Text="View" CssClass="btn" OnClick="cmdLstSel_Click" />
                </td>
            </tr>

        </SelectedItemTemplate>
        <LayoutTemplate>
            <table runat="server">
                <tr runat="server">
                    <td runat="server">
                        <table id="itemPlaceholderContainer" runat="server" border="0" style="">
                            <tr runat="server" style="">
                                <th runat="server">FirstName</th>
                                <th runat="server">LastName</th>
                                <th runat="server">HotelName</th>
                                <th runat="server">City</th>
                                <th runat="server">View</th>
                            </tr>
                            <tr id="itemPlaceholder" runat="server">
                            </tr>
                        </table>
                    </td>
                </tr>
                <tr runat="server">
                    <td runat="server" style="">
                        <asp:DataPager ID="DataPager1" runat="server">
                            <Fields>
                                <asp:NextPreviousPagerField ButtonType="Button" ShowFirstPageButton="True" ShowLastPageButton="True" />
                            </Fields>
                        </asp:DataPager>
                    </td>
                </tr>
            </table>
        </LayoutTemplate>
    </asp:ListView>

So we can highlight the row clicked with:

   protected void ListView1_SelectedIndexChanging(object sender, ListViewSelectEventArgs e)
    {
        
    }

    protected void ListView1_SelectedIndexChanged(object sender, EventArgs e)
    {
        GPayments.DataSource = MyRst("SELECT * FROM HotelPayments WHERE Hotel_ID = " + hID);
        GPayments.DataBind();
    }

Now if I leave out the re-bind, then of course the row will highlight, but of course it is the "previous" row that hight lights.

And if I could set the class of the ONE row, then I could dump the selected item template.

You can do this with GREAT ease in a GridView, and I often do this:

    Dim gRow As GridViewRow = -- get any row

    gRow.CssClass = " alert-info"

however, I would like to do the same with listView. When I do above for GridView, then I don't need or have to bother with a re-bind, and I don't even need a selected template either.

So left is a grid view, and we get this:

enter image description here

However, I want to do this with listview. (and WITHOUT having to do a re-bind).

Any simple way to highlight a row in ListView WITHOUT a re-bind?

Upvotes: 1

Views: 183

Answers (1)

Albert D. Kallal
Albert D. Kallal

Reputation: 49169

Ok, a bit of googling, and the solution becomes VERY easy.

The goal here is to click on a row - highlight that row.

Of course WAY too much work to have to include a selected row template.

It is a better trade off to add 3 lines of code to do this.

So, say we have this markup:

    <asp:ListView ID="ListView1" runat="server" DataKeyNames="ID" 
        OnSelectedIndexChanged="ListView1_SelectedIndexChanged" OnSelectedIndexChanging="ListView1_SelectedIndexChanging" >
        <ItemTemplate>
            <tr id="mytr" runat="server">
                <td><asp:Label ID="FirstNameLabel" runat="server" Text='<%# Eval("FirstName") %>' /></td>
                <td><asp:Label ID="LastNameLabel" runat="server" Text='<%# Eval("LastName") %>' /></td>
                <td><asp:Label ID="HotelNameLabel" runat="server" Text='<%# Eval("HotelName") %>' /></td>
                <td><asp:Label ID="CityLabel" runat="server" Text='<%# Eval("City") %>' /></td>
                <td>
                    <asp:Button ID="cmdLstSel" runat="server" Text="View" CssClass="btn" 
                        CommandName="Select" OnClick="cmdLstSel_Click"/>
                </td>
            </tr>
        </ItemTemplate>
        <LayoutTemplate>
                <table id="itemPlaceholderContainer" runat="server" border="0" class="table table-hover" style="">
                    <tr runat="server" style="">
                        <th runat="server">FirstName</th>
                        <th runat="server">LastName</th>
                        <th runat="server">HotelName</th>
                        <th runat="server">City</th>
                        <th runat="server">View</th>
                    </tr>
                    <tr id="itemPlaceholder" runat="server">
                    </tr>
                </table>
        </LayoutTemplate>
    </asp:ListView>

ok, our code to fill is this:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
            LoadView();
    }
}
void LoadView()
    {
        ListView1.DataSource = MyRst("SELECT TOP 12 * FROM tblHotels ORDER BY HotelName");
        ListView1.DataBind();
    }

Output:

enter image description here

Ok, so for the row click? Well, we don't have to use the selected index changed, but, for this we will (so CommandName="Select" is what triggers that index changed event).

However, I want a simple button click, and with some code (to display the details part).

So, our button click is this:

protected void cmdLstSel_Click(object sender, EventArgs e)
    {
        Button btn = (Button)sender;
        ListViewDataItem gRow = (ListViewDataItem)btn.Parent.Parent.Parent;

        int hID = (int)ListView1.DataKeys[gRow.DisplayIndex]["ID"];
        GHotelOptions.DataSource = MyRst("SELECT * FROM HotelOptions WHERE Hotel_ID = " + hID);
        GHotelOptions.DataBind();

        GPayments.DataSource = MyRst("SELECT * FROM HotelPayments WHERE Hotel_ID = " + hID);
        GPayments.DataBind();

    }

Above will fill the child tables. Note the cool trick to get the row - I don't bother with the listview event model!

Now for the row highlight.

The trick is to add an "id" to the tr row like this:

 <ItemTemplate>
      <tr id="mytr" runat="server">

So, we can now pick up the tr element.

So on lv index changed, we do this:

    protected void ListView1_SelectedIndexChanged(object sender, EventArgs e)
    {

        ListViewItem gRow = (ListViewItem)ListView1.Items[ListView1.SelectedIndex];
        if ( (ViewState["MySel"] != null) && ((int)ViewState["MySel"] != gRow.DataItemIndex) )
        {
            ListViewItem gLast = ListView1.Items[(int)ViewState["MySel"]];
            HtmlTableRow hTRL = (HtmlTableRow)gLast.FindControl("mytr");
            hTRL.Attributes.Add("class", "");
        }
        HtmlTableRow hTR = (HtmlTableRow)gRow.FindControl("mytr");
        hTR.Attributes.Add("class", "alert-info");

        ViewState["MySel"] = gRow.DataItemIndex;
   }

So, I did use row state, but that lets me un-highlight + highlight, and I do NOT hve to re-bind the grid.

And I just picked a nice boot strap class - it even "reverses" the text - very nice.

So now we get this: enter image description here

So this did cost about 4-5 extra lines. But, we trade that for NOT having a selected template in the lv (and that's too much to maintain both the row layout and THEN have to maintains the same for selected template. And worse, you STILL had to re-bind for the highlighted row click to show. This way, we don't.

I also used a "helper" routine to get a datatable, and that was this:

public DataTable MyRst(string strSQL)
{
    DataTable rstData =  new DataTable();
    using (SqlCommand cmdSQL = new SqlCommand(strSQL,
        new SqlConnection(Properties.Settings.Default.TEST3)))
    {
        cmdSQL.Connection.Open();
        rstData.Load(cmdSQL.ExecuteReader());
    }
    return rstData;
}

At the end of the day, we can now highlight the row, do so with a click, and we could even move the selected index changed code to our button code and not even use the lv index and built in events.

Upvotes: 1

Related Questions