Devils Work

—Blog By DotNetRuler

  • Categories

  • Archives

How to make a Gridview Row Color/ Cell Color/ Text Color

Posted by DotnetRuler on October 13, 2009

In this article I am going to explain how we can change the Gridview Row Color/ Cell Color/ Text Color. So many people asked in the emails for my previous article why I have used Template Columns rather than bound fields. I just want to make them clear this question (going to explain it at the end of the article) because, I am going to use Template Fields again in this article 🙂

TASK: In this article we are trying to display some information from AdventureWorks database, Employee table, and if the employee pay rate is more than 25 we are going to change the color of the row/cell/text.

GridView Row Color

Here is the html markup for the grid

<asp:GridView ID=”GridView1″ runat=”server” OnRowDataBound=”GridView1_RowDataBound” AllowSorting=”true” AllowPaging=”true” PageSize=”10″ AutoGenerateColumns=”false” >

<Columns>

                <asp:TemplateField HeaderText=”ID”>

                    <ItemTemplate>

                        <asp:Label runat=”server” ID=”lblNationalID” Text='<%#Eval(“NATIONALIDNUMBER”)%>’ />

                    </ItemTemplate>

                </asp:TemplateField>               

                <asp:TemplateField HeaderText=”Title”>

                    <ItemTemplate>

                        <asp:Label runat=”server” ID=”lblTitle” Text='<%#Eval(“TITLE”) %>’ />

                    </ItemTemplate>                   

                </asp:TemplateField>

                <asp:TemplateField HeaderText=”Manager ID”>

                    <ItemTemplate>

                        <asp:Label runat=”server” ID=”lblMgrID” Text='<%#Eval(“MANAGERID”) %>’ />

                    </ItemTemplate>                   

                </asp:TemplateField>

                <asp:TemplateField HeaderText=”Gender”>

                    <ItemTemplate>

                        <asp:Label runat=”server” ID=”lblGender” Text='<%#Eval(“GENDER”) %>’ />

                    </ItemTemplate>                   

                </asp:TemplateField>

                <asp:TemplateField HeaderText=”Rate”>

                    <ItemTemplate>

                        <asp:Label runat=”server” ID=”lblRate” Text='<%#Eval(“RATE”) %>’ />

                    </ItemTemplate>                   

                </asp:TemplateField>               

            </Columns>

</asp:GridView>

The Above markup is pretty simple if you follow my previous article as I just used template field’s and Item templates.  The only thing special piece from the previous article is OnRowDataBound=”GridView1_RowDataBound”. I implemented the rowdatabound event. This event fires after we call DataBind() method.  If we want to modify data or check certain conditions before displaying it to the user this is the correct place to do the changes. As we need to change the row color/ text color/ cell color before displaying to the user this we need this event.

The rowdatabound signature is as follows.

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)

As we can see, it has two parameters. The first one is sender, so in this case it is gridview which is calling this event. And the second one is GridViewRowEventArgs.  This is very helpful parameter which carries all the row information like what kind of row (data row/ header row/ footer row)? What is the row state (Alternate/ Insert/ Edit/ Selected …)? And many more, we can explore it at here.

Coming to the c# code my page load event is as follows.

protected void Page_Load(object sender, EventArgs e)

    {       

        if (!Page.IsPostBack)

        {

            using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings[“AdventureWorksConnectionString”].ConnectionString))

            {

                conn.Open();

                using (SqlCommand comm = new SqlCommand(“GetEmployeeWithSalaries”, conn))

                {

                    comm.CommandType = CommandType.StoredProcedure;

                    SqlDataAdapter da = new SqlDataAdapter(comm);

                    DataSet ds = new DataSet();

                    da.Fill(ds);

                    GridView1.DataSource = ds;

                    GridView1.DataBind();

                }

            }

        }

    }

I am just opening a connection and calling a stored procedure, getting the data back into a dataset and binding to the grid.

As I said earlier as soon as the DataBind() called, our RowDataBound event fires. The event code is as follows.

    /// <summary>

    /// Row Data Bound Event fires after gridview calls DataBind() method.

    /// So if you want to data or check certain conditions before displaying it to the user

    /// this may be correct place to do the changes.

    /// </summary>

    /// <param></param>

    /// <param></param>

    protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)

    {       

        // Check the row type, if “datarow” enter

        if (e.Row.RowType == DataControlRowType.DataRow)

        {

            // grab the Label Control.

            Label lblRate = e.Row.FindControl(“lblRate”) as Label;

 

            // get the value from the datasoure like this

            Double rate = Convert.ToDouble(Convert.ToString(DataBinder.Eval(e.Row.DataItem, “Rate”)));

 

            // get the whole dataItem, if u want to access more columns from database like this           

            // It is a datarowview if u bind dataset/datatable

            // DataRowView dr = e.Row.DataItem as DataRowView;

 

            // after you got the datarowview u can access the column value like this.

            // string s = dr[“Rate”].ToString();

 

            // It is a datarowview if u bind List<Employee>

            // Employee employee = e.Row.DataItem as Employee;

 

            // after you got the datarowview u can access the property value like this.

            // string rate = employee.Payrate;

           

            if (rate > 25.00)

            {

                // grab the cell where that label resides

                DataControlFieldCell d = lblRate.Parent as DataControlFieldCell;

 

                // change the backcolor like this

                d.BackColor = System.Drawing.Color.Red;

 

                // change the row color like this

                e.Row.BackColor = System.Drawing.Color.LightBlue;

 

                // change the text color like this

                lblRate.ForeColor = System.Drawing.Color.White;

            }

        }

    }

If we see in the code, I am checking a condition such that if the row is of type datarow then only it goes into that loop as we don’t need to change any colors in the header/footer. So once the row is of type datarow it goes into the loop. We need to get the label control from the row using findcontrol method. FindControl method takes the control name as the parameter. So as we can see in the code we are passing the “lblRate” which is the name of the label control in the Gridview html markup. Findcontrol returns a web.control, so we need to cast it to the appropriate type, in our case it is label.

Next step is needed to get the rate. we can get it in different ways. The basic thing is GridViewEventArgs carries the whole row data in the e.Row.DataItem Object. This object varies with the type of data source. If we bind dataset/datatable it would be datarowview, if it is List<T> it would be of type T. We need to cast it to the appropriate type and access the inner properties of the object.

Last step is needed to change the color

Change the color of row: GridViewEventArgs has a property called e.Row.BackColor we can assign a color to it. This will do the work for us.

Change the color of cell: so we don’t know what cell we need to change the color. We just know that we need to change the color of the cell where our rate column resides and in our example we placed the lblRate control in that cell. So cell will be the parent of our label control. So get the parent using parent property of the label and cast it to the appropriate type. I know some people might be confused by now as I am always saying “cast it to the appropriate type”. To find out the appropriate type just put a break point and check lblRate.Parent.GetType(), which will gives us the parent type. No one is going to know this for the first time. We just need to do some reverse engineering to achieve what we need. Once you got the parent (cell) we can change the backcolor using backcolor property of it.

Change the text color: The text that we r displaying is label controls content. So we just need to change the label forecolor property.

Lastly Why TempalteFields? Why not BoundFields?

Note:  some people will think why don’t we achieve this functionality with the boundfieldcolumns? Why templatefields?

The reason is because, it’s very hard to manage the code and if we use cells [index] what if we want to change the column position in future? We need to change the code base again. In the above case we just need to change the markup if you use tempaltefields which we can do it easily and which does not need a project build. What if we need to place multiple controls in the same column? And there will be so many other conditions to. So this is the reason why we are using Tempaltefields rather than Boundfields.

Note: WordPress text editor has some problems, I will re-edit the post when it is ready.

Happy Coding .

Keep Rocking as always 🙂

DotNetRuler.

Posted in ASP.NET, Grid View | 11 Comments »

GridView Row Edit, Delete and Update

Posted by DotnetRuler on March 27, 2009

In this Post I am going to explain a simple light weight GridView Edit, Delete, and Update functionality.  We are going to apply this functionality on Northwind Database, Employee table.

Following are the screen shots.

normal-vieweditmodeview

 

First of all I am going to explain about creating a Connection String.

Connection String has mainly 3 properties.

DataSource — DataSource is your SQL Server name.

Initial Catalog — Your Database name (Northwind in this case).

Integrated Security – True

Integrated Security will access the SQL Server with the current windows identity established on the Operating System. For more information about Integrated Security refer this. We usually place the connection string in the Web.config file under “Configuration ==> ConnectionStrings” section.

Here is my connection string.

<connectionStrings>

 

    <add name=NorthwindConnectionString connectionString=Data Source=*****(SQL Server Name);Initial Catalog=NorthWind;Integrated Security=True;/>

  </connectionStrings>

To learn more about different type of connection strings refer this.

Then, after we are done with your connection string in the Web.config file let’s move on to the C# code.

The Following Snippet is to bind GridView.

private void BindGridData()

  {

    using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings[“NorthwindConnectionString”].ConnectionString))

      {

          conn.Open();

          using (SqlCommand comm = new SqlCommand(“select E.EmployeeID,E.FirstName,E.LastName,E.Title,E.Country from Employees E”, conn))

          {

               SqlDataAdapter da = new SqlDataAdapter(comm);

               DataSet ds = new DataSet();

               da.Fill(ds);

               GridView1.DataSource = ds;

               GridView1.DataBind();

          }

      }

  }

The First Line using statement allows the programmer to specify when objects that use resources should release them. The object provided to the using statement must implement the IDisposable interface. This interface provides the Dispose method, which should release the object’s resources. Refer this for Complete Reference.

The following is how we write asp.net GridView web server control code in aspx page.  I guess most of the people will be aware of the GridView events. For complete Reference refer this.

In the Code you can see I put AutoGenerateColumns=”false”. That means I have to write column names whatever I want to show to the user. If we put AutoGenerateColumns=”True”, that means u don’t have to write any custom code on your page and user can see each and every column in your dataset or datatable whatever you are binding to your gridview.

It is always good to have some control on these instead of giving up everything to it. I want to hide EmployeeID   for the user.  But I need it for querying the databse while updating and deleting  the user stuff.  So

How can we hide a column in a GridView and access it in the Code behind ?

We can do this in several ways!!! , But depends on what column we want to hide. I always follow this method.

Writing a Template Field and making it invisible.  In the template field I will Place a label or some controls, So that it’s very easy to access those controls in the code behind by using FindControl method.

Suppose if we are trying to hide primary key of our table, there is actually no need to hide. GridView has a Property called DataKeyNames. We have to give our primary key column name to it. It will do the rest.  we can see how we can access that in the code behind in the GridView_Rowupdating Event which I am going to explain later part of this article.

What is TemplateField, ItemTemplate, and EditItemTemplate?

We will use Template Field, whenever we want to define some custom control in the data bound controls like GridView, DataGrid or DataRepeater.

ItemTemplate is the content to display for the items in the TemplateField. 

EditItemTemplate as the name itself it is the content to display for the items in the TemplateField when it is in Edit mode. Refer this for complete reference.

Take this simple Snippet.

<asp:TemplateField HeaderText=”LastName”>

     <ItemTemplate>

            <asp:Label runat=”server” ID=”LastName” Text=’<%#Eval(“LastName”) %> />

     </ItemTemplate>

     <EditItemTemplate>

          <asp:TextBox runat=”server” ID=”txtLastName” Text=’<%#Eval(“LastName”) %> />

          <asp:RequiredFieldValidator runat=”server” ID=”rfdLastName”                                       ControlToValidate=”txtLastName” ValidationGroup=”var1″ ErrorMessage=”*” />

     </EditItemTemplate>

</asp:TemplateField>

 

In the above Snippet you are seeing a label in Item Template that means whenever we are showing GridView to the user Label will be visible to the user. If he clicks edit (or) in the edit mode he can be able to see the Textbox.

<asp:BoundField HeaderText=”FirstName” DataField=”FirstName” ReadOnly=”false”/>

The above piece of code will also do the same as label in ItemTemplate and Textbox in the EditItemTemplate. By default all the boundfields will be trasferred as Textboxes in Edit Mode. To avoid this we need to keep the property ReadOnly as false, Then in the edit mode nothing will happenes. It just visible like a label.

 

The reason I use TemplateField instead of BoundField is that, it is very easy to grab those controls in the codebehind if we user labels or textboxes. In case of the bound field’s we need to check what column it is and need to use index of that cloumn, which is little hard and even in future if we change the column order  we have to change the code too.

 

<asp:GridView ID=”GridView1″ runat=”server” GridLines=”None” AutoGenerateColumns=”false”

      AlternatingRowStyle-BackColor=”#EEEEEE” EditRowStyle-BorderColor=”Red”

      onrowcancelingedit=”GridView1_RowCancelling” onrowcommand=”GridView1_RowCommand”

      onrowdeleting=”GridView1_RowDeleting” onrowediting=”GridView1_RowEditing”

      onrowupdating=”GridView1_RowUpdating” DataKeyNames=”EmployeeID”>           

      <Columns>           

         <asp:TemplateField Visible=”false” HeaderText=”EmployeeID”>

            <ItemTemplate>

              <asp:Label runat=”server” ID=”EmployeeID” Text=’<%#Eval(“EmployeeID”)%> />

            </ItemTemplate>

         </asp:TemplateField>

         <%–<asp:BoundField HeaderText=”FirstName” DataField=”FirstName” />–%>

 

         <asp:TemplateField HeaderText=”LastName”>

 

            <ItemTemplate>

              <asp:Label runat=”server” ID=”LastName” Text=’<%#Eval(“LastName”) %> />

            </ItemTemplate>

 

            <EditItemTemplate>

            <asp:TextBox runat=”server” ID=”txtLastName” Text=’<%#Eval(“LastName”) %> />

            <asp:RequiredFieldValidator runat=”server” ID=”rfdLastName”                    ControlToValidate=”txtLastName” ValidationGroup=”var1″ ErrorMessage=”*” />

            </EditItemTemplate>

 

         </asp:TemplateField>

         <asp:TemplateField HeaderText=”Title”>

 

            <ItemTemplate>

              <asp:Label runat=”server” ID=”Title” Text=’<%#Eval(“Title”) %> />

            </ItemTemplate>

 

            <EditItemTemplate>

              <asp:TextBox runat=”server” ID=”txtTitle” Text=’<%#Eval(“Title”) %> />

              <asp:RequiredFieldValidator runat=”server” ID=”rfdTitle”                       ControlToValidate=”txtTitle” ValidationGroup=”var1″ ErrorMessage=”*” />

            </EditItemTemplate>

 

         </asp:TemplateField>

 

         <asp:TemplateField HeaderText=”Country”>

        

           <ItemTemplate>

             <asp:Label runat=”server” ID=”Country” Text=’<%#Eval(“Country”) %> />

           </ItemTemplate>

 

           <EditItemTemplate>

             <asp:TextBox runat=”server” ID=”txtCountry” Text=’<%#Eval(“Country”) %> />

             <asp:RequiredFieldValidator runat=”server” ID=”rfdCountry”                 ControlToValidate=”txtCountry” ValidationGroup=”var1″ ErrorMessage=”*” />

           </EditItemTemplate>

 

          </asp:TemplateField>

 

      <asp:TemplateField HeaderText=”Action”>

 

      <ItemTemplate>

      <asp:LinkButton ID=”btnEdit” Text=”Edit” runat=”server” CommandName=”Edit” />

      <br />

      <asp:LinkButton ID=”btnDelete” Text=”Delete” runat=”server” CommandName=”Delete” />

      </ItemTemplate>

 

      <EditItemTemplate>

      <asp:LinkButton ID=”btnUpdate” Text=”Update” runat=”server” CommandName=”Update” />

      <asp:LinkButton ID=”btnCancel” Text=”Cancel” runat=”server” CommandName=”Cancel” />

      </EditItemTemplate>

 

      </asp:TemplateField>

 

   </Columns>

</asp:GridView>

If you see the Last TemplateField part in the above code, I am using the link buttons for edit, update, delete and cancel. May be you may think why am I using link buttons as we are provided with some command field buttons by GridView.

1)      If we use command buttons we have less control on them while doing validations, i.e. while assigning validation groups.

2)      Secondly if you want to include a custom field (some button or link) in the same column it’s not possible.

If we use proper command names for the buttons like “EDIT”, “DELETE”, “UPDATE”, “CANCEL” these will also trigger the appropriate GridView Events.

Ok let’s move on to Code behind what we have to do when user clicks Edit, Delete, Update and Cancel

When we click on Edit the OnRowEditing event will be fired. You can see the C# code below

protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)

{

   GridView1.EditIndex = e.NewEditIndex;

   BindGridData();

}

In the above code snippet as you see GridViewEditEventArgs will give the row number whatever you are editing by NewEditIndex property. So GridView will put the appropriate row into the Edit Mode by assigning row number to its EditIndex property. Then again we have to call that BindGridData () method to bind data for the textboxes.

So once after done with editing data, if we click update the following method will be triggered. It will call OnRowUpdating Event.  

1)      The First line is to get the Primary Key of the table using DataKeyNames Property of GridView.

2)      The Second line is to access the value of the invisible column.

protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)

{

   string s = GridView1.DataKeys[e.RowIndex].Value.ToString();           

   Label EmployeeID = GridView1.Rows[e.RowIndex].FindControl(“EmployeeID”) as Label;

   TextBox LastName = GridView1.Rows[e.RowIndex].FindControl(“txtLastName”) as TextBox;

   TextBox Title = GridView1.Rows[e.RowIndex].FindControl(“txtTitle”) as TextBox;

   TextBox Country = GridView1.Rows[e.RowIndex].FindControl(“txtCountry”) as TextBox;

   String UpdateQuery = string.Format(“UPDATE Employees SET LastName='{0}’,

                        Title='{1}’,Country='{2}’ WHERE EmployeeID = {3}”,LastName.Text, Title.Text, Country.Text, Convert.ToInt32(EmployeeID.Text));

 

    GridView1.EditIndex = -1;

    BindGridData(UpdateQuery);

}

Once we access the required fields in the code behind, we need to update the data in the database and show the updated data to the user. So am calling the method BindGridData method which is overloaded . I am passing Update Query as a parameter to it. You can see that method in the following snippet.

private void BindGridData(string Query)

{

  string connectionstring  =        ConfigurationManager.ConnectionStrings[“NorthwindConnectionString”].ConnectionString;

 

  using (SqlConnection conn = new SqlConnection(connectionstring))

  {

    conn.Open();

    using (SqlCommand comm = new SqlCommand(Query +

                  “;select E.EmployeeID,E.FirstName,E.LastName,E.Title,E.Country from Employees E”, conn))

    {

        SqlDataAdapter da = new SqlDataAdapter(comm);

        DataSet ds = new DataSet();

        da.Fill(ds);

        GridView1.DataSource = ds;

        GridView1.DataBind();

    }

  }

}

If the user click cancels the following event (OnRowCancelling) will be fired. When you are setting the value of the EditIndex to -1 that means you are exiting from the editmode.  So i.e. when user clicks cancel, here we are exiting from the editmode and rebinding the data to the GridView by calling BindGridData method.

protected void GridView1_RowCancelling(object sender, GridViewCancelEditEventArgs e)

{

    GridView1.EditIndex = -1;

    BindGridData();

}

If the user clicks the Delete button OnRowDeleting event will be fired. The following is the code for that event. Going into that code we are trying to get the primary key of the employee table(EmployeeID) by using GridView DataKeyNames and then  pass the Query to the BindGridData method to bind the updated data to the GridView.

protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)

{

    string EmployeeID = GridView1.DataKeys[e.RowIndex].Value.ToString();

    string Query = “delete Employee where Employee.EmployeeID = “ + EmployeeID;

    BindGridData(Query);

}

 

Happy Coding .

Keep Rocking as always J

DotNetRuler. 

Posted in ASP.NET, Grid View | Tagged: , | 67 Comments »