tags:

views:

393

answers:

2

Ok so I have a GridView like this:

<asp:GridView ID="gv" runat="server" ... >
...
<HeaderStyle CssClass="header" />
<RowStyle CssClass="datarow" />
<AlternatingRowStyle CssClass="datarow alt" />
<Columns>
    <asp:TemplateField>
        <ItemTemplate>
            <asp:CheckBox runat="server" ID="gvchkDelete" />
        </ItemTemplate>
    </asp:TemplateField>
</Columns>
...
</asp:GridView>

Notice the custom RowStyle and AlternatingRowStyle css classes. What I want is to change the row's style whenever the gvchkDelete CheckBox is selected, and remove it when it's not. So I came up with something like this:

protected void gv_PreRender(object sender, EventArgs e)
{
    DUtil.GridViewRowHighlight(gv, "gvchkDelete");
}

//External Class
public class DUtil
{
public static void GridViewRowHighlight(GridView gv, string CheckBoxControlID)
{
    foreach (GridViewRow gvr in gv.Rows) {
        GridViewRowHighlight(gvr, CheckBoxControlID);
    }
}

public static void GridViewRowHighlight(GridViewRow gvr, string CheckBoxControlID)
{
    string scriptFormat = "if(this.checked){{document.getElementById('{0}').className+=' {1}';}}else{{document.getElementById('{0}').className=document.getElementById('{0}').className.replace('{1}','');}};";
    string script = String.Format(scriptFormat, gvr.ClientID, DEstilos.HighlightStyle);
    CheckBox chk = (CheckBox)gvr.FindControl(CheckBoxControlID);
    if (chk.Checked) AddCssClass(gvr, DEstilos.HighlightStyle);
    else RemoveCssClass(gvr, DEstilos.HighlightStyle);
    chk.Attributes.Add("onclick", script);
}

public static void AddCssClass(WebControl control, string cssClass)
{
    List<string> classes = new List<string>(control.CssClass.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
    classes.Add(cssClass);
    control.CssClass = ToDelimitedString(classes, " ");
}

public static void RemoveCssClass(WebControl control, string cssClass)
{
    List<string> classes = new List<string>(control.CssClass.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
    classes.Remove(cssClass);
    control.CssClass = ToDelimitedString(classes, " ");
}

public static string ToDelimitedString(IEnumerable<string> list, string delimiter)
{
    StringBuilder sb = new StringBuilder();
    foreach (string item in list) {
        if (sb.Length > 0)
            sb.Append(delimiter);

        sb.Append(item);
    }
    return sb.ToString();
}
//End class
}

//External Class
public class DEstilos
{
public const string HighlightStyle = "highlight";
//End Class
}

What all of that does is: for every checkbox in the gridview.Rows collection add a JavaScript function to the checkbox's onclick attribute so that when it's clicked the checkbox's parent row it's added/removed the Highlight style. And also if the checkbox is checked/unchecked by default then add/remove the highlight style.

All of this just to ensure that whenever a postback is made the rows with a selected checkbox conserved the Highlight style (witch doesn't happen by just enabling viewstate of course). The problem is that the RowStyle and AlternatingRowStyle css classes defined in the gridview's markup seems to be getting "ignored" or "removed", Why?

UPDATE: Solutions without using jQuery or Prototype would be better, except if that's the only way of doing this of course.

UPDATE 2, 3: If you remove the lines:

if (chk.Checked) AddCssClass(gvr, DEstilos.HighlightStyle);
else RemoveCssClass(gvr, DEstilos.HighlightStyle);

from the GridViewRowHighlight method, then the RowStyle and AlternatingRowStyle css classes DO get added to the HTML markup and I get the desired effect, but on every postback the highlight effect is removed, while the checkbox maintains it's previous state.

Thanks for all your help!

+2  A: 

This is a prime candidate for jQuery, I believe. Tweaking CSS classes for HTML controls is a cinch with jQuery.

Jagd
http://docs.jquery.com/Attributes/addClass
jrummell
+1  A: 

It sounds like you have two issues:

  1. The CSS classes you're setting aren't being respected when the page is rendered.
  2. You want check box behavior for each row of the grid to toggle the style of its parent grid row.

Try this for problem #2:

Change <asp:CheckBox runat="server" ID="gvchkDelete" /> to <asp:CheckBox runat="server" ID="gvchkDelete" OnClientClick="javascript:ToggleHighlight(this);" />

Add this javascript function and make sure its accessible by the page your loading:

function ToggleHighlight(elem)
{  
  if(!elem)
  {
    return;
  }

  var gridRow = elem;

  while(gridRow.tagName != "TR" && gridRow.parentNode)
  {
    gridRow = gridRow.parentNode;
  }

  gridRow.className = elem.checked ? 
                      (gridRow.className + " highlight") :
                      gridRow.className.replace("highlight", "");
}

As for problem #1, please verify that your CSS styles do make their way to the rendered page.

For an alternative approach that gets around server-side code, you can do the following on page load (this uses the jQuery library):

$(document).ready
(
  function()
  {
    $("input[id$=gvchkDelete]")
      .each
      (
        function()
        {
          ToggleHighlight(elem);
        }
      );
  }
);
David Andres
When I remove the lines on Update 2,3. The css is redered correctly.
Unlimited071
@Unlimited071: That code needs to be there. Correct me if I'm mistaken, but first page load has nothing selected. Your click handlers work fine, so rows will be highlighted correctly. However, when you post back all of the coloring is lost. That's why you need that code you removed.
David Andres
@David: yes, that's correct. That's why I put it in the first place, but if I leave the lines unchanged then the classes defined in the rowstyle and alternatingrowstyle tags don't make it to the HTML
Unlimited071
@Unlimited071: The GridView control has a SelectedRowStyle property. Can you use this instead? See http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.selectedrowstyle.aspx for more details.
David Andres
@Unlimited071: I've added a JavaScript/jQuery-oriented approach that will highlight rows after page load on the client. This approach will allow you to remove the server-side class assignments.
David Andres