How to implement conditional formatting in a GridView - c#

I have a GridView on my aspx page which displays a collection of objects defined by the following class
public class Item
{
public string ItemName{get; set;}
public object ItemValue{get; set;}
}
Then in my aspx markup I have something like this
<asp:GridView ID="MyTable" runat="server">
<Columns>
<asp:BoundField DataField="ItemName" />
<asp:BoundField DataField="ItemValue" />
</Columns>
</asp:GridView>
What I want to know is:
Is there a way to use conditional formatting on the ItemValue field, so that if the object is holding a string it will return the string unchanged, or if it holds a DateTime it will displays as DateTime.ToShortDateString().

Not sure if you can use a BoundField, but if you change it to a TemplateField you could use a formatting function like in this link.
ie something like
<%# FormatDataValue(DataBinder.Eval(Container.DataItem,"ItemValue")) %>
Then in your codebehind, you can add a Protected Function
Protected Function FormatDataValue(val as object) As String
'custom enter code hereformatting goes here
End Function
Or you could do something in the OnRowCreated event of the gridview, like in this link
<asp:GridView ID="ctlGridView" runat="server" OnRowCreated="OnRowCreated" />
this function is conditional formatting based on whether or not the datavalue is null/is a double
protected void OnRowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataRowView drv = e.Row.DataItem as DataRowView;
Object ob = drv["ItemValue"];
if (!Convert.IsDBNull(ob) )
{
double dVal = 0f;
if (Double.TryParse(ob.ToString(), out dVal))
{
if (dVal > 3f)
{
TableCell cell = e.Row.Cells[1];
cell.CssClass = "heavyrow";
cell.BackColor = System.Drawing.Color.Orange;
}
}
}
}
}

With BoundField you should modify your Item class.
If you don't want to modify your CodeBehind ther is a sort of trick you can do using a TemplateField:
<asp:GridView ID="MyTable" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="ItemName" HeaderText="Name" />
<asp:TemplateField HeaderText="Value">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# ((Eval("ItemValue") is DateTime) ? ((DateTime)Eval("ItemValue")).ToShortDateString() : Eval("ItemValue")) %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
obviously you can do it for any type of object but maybe your "Text" field would become.. complicated..
by the way.. my CodeBehind for this example was just you class Item and this Page_Load():
protected void Page_Load(object sender, EventArgs e)
{
Item i1 = new Item();
i1.ItemName = "name1";
i1.ItemValue = "foo";
Item i2 = new Item();
i2.ItemName = "name2";
i2.ItemValue = DateTime.Now;
List<Item> list1 = new List<Item>();
list1.Add(i1);
list1.Add(i2);
MyTable.DataSource = list1;
MyTable.DataBind();
}
and the result was correct ;)

i decided with the Paul Rowland solution and more one thing "if (e.Item.DataItem is DataRowView)":
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
if (e.Item.DataItem is DataRowView)
{
DataRowView rowView = (DataRowView)e.Item.DataItem;
String state = rowView[PutYourColumnHere].ToString();
if (state.Equals("PutYourConditionHere"))
{
//your formating, in my case....
e.Item.CssClass = "someClass";
}
}
}

In .NET 2.0 is even easier:
Add this method to code behind: (this example formats a double value as million with 1 digit)
public string EvalAmount(string expression)
{
double? dbl = this.Eval(expression) as double?;
return dbl.HasValue ? string.Format("{0:0.0}", (dbl.Value / 1000000D)) : string.Empty;
}
In the aspx code, use this:
<asp:TemplateField ItemStyle-Width="100px">
<ItemTemplate>
<asp:Label runat="server" Text='<%# EvalAmount("MyAmount") %>'></asp:
</ItemTemplate>
</asp:TemplateField>

Related

Enable or disable a HyperLink in the RowDataBound-event

I have a problem with my code. I need enable or disable a HyperLink in the RowDataBound event in an ASP.NET GridView based on a value extracted from the database.
If the value of field File of my database is not null, the HyperLink is visible otherwise not. In GridView, I don't have planned to show the value of field File.
I've tried using these solution without success, because I have this error.
Compiler Error Message: CS1502: The best overloaded method match for 'string.IsNullOrEmpty(string)' has some invalid arguments
Here is my code:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
HyperLink Srl = (HyperLink)e.Row.FindControl("Srl");
foreach (string color in colorList)
{
if (!string.IsNullOrEmpty(DataBinder.Eval(e.Row.DataItem, "File")))
{
Srl.Visible = true;
}
}
}
}
DataBinder.Eval returns an object. You need to convert that to a String.
Try this:
if (!string.IsNullOrEmpty(Convert.ToString(DataBinder.Eval(e.Row.DataItem, "File"))))
{
Srl.Visible = true;
}
<asp:GridView ID="gvList" runat="server" Width="100%" AutoGenerateColumns="False" AllowPaging="false">
<Columns>
<asp:TemplateField HeaderText="Select">
<ItemTemplate>
<asp:CheckBox ID="cbSelect" runat="server" />
<asp:HiddenField ID="hfSLNO_BARCODE" runat="server"
Value='<%#Bind("SLNO_BARCODE") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Use asp:HiddenField for File value and use this in row data bound event.
void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
HyperLink Srl = (HyperLink)e.Row.FindControl("Srl");
foreach (string color in colorList)
{
string str = (string)DataBinder.Eval(e.Row.DataItem, "File");
//then you can check
if (!String.IsNullorEmpty(str ))
{
Srl.Visible = true;
}
}
}
}

How to style Asp.net GridView cells with colour based on cell value

I have a Gridview , it have a column called student_Class. There are around of 80 Class on grid view. I have grouped this class using GroupBy query.
Now I want to Style this different class with different color. How is it possible?
It is not easy to write all classes on RowDataBound and giving color.
Is there any other way?
Code:
groups = (ArrayList)Session["selectedclass"];
SELECT id,name,student_Class FROM student where
student_Class='"+groups[0].ToString().Trim()+"'
group by student_Class.
Gives Data as
id name student_class
1 aa A
2 bb A
3 cc A
4 dd B
5 ee B
6 as B
7 ss B
8 AZZ D
The student class with value A need same color(for cell) and B need other color., etc.
ASPX:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="id" DataSourceID="SqlDataSource1"
ondatabound="GridView1_DataBound" onrowdatabound="GridView1_RowDataBound">
<Columns>
<asp:BoundField DataField="id" HeaderText="id" ReadOnly="True"
SortExpression="id" />
<asp:BoundField DataField="name" HeaderText="name" SortExpression="name" />
<asp:BoundField DataField="student_class" HeaderText="student_class"
SortExpression="student_class" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:SiteConnectionString %>"
SelectCommand="SELECT * FROM [student]">
</asp:SqlDataSource>
Code behind:
static string[,] ClassNames =
{
{"A","Red"},
{"B","Blue"},
{"C","Pink"},
{"D","Green"},
// and so on
};
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
string className = e.Row.Cells[2].Text;
string color = "Black";
for (int i = 0; i <= ClassNames.GetUpperBound(0); i++)
{
if (ClassNames[i, 0] == className)
{
color = ClassNames[i, 1];
e.Row.Cells[2].ForeColor = Color.FromName(color);
e.Row.Cells[2].BorderColor = Color.Black;
break;
}
}
}
If you only want to style depend on the value, I must recommend you to do it client-side, by using Jquery or javaScript.
Also, it won't affect performance as it's on the client-side rather than doing it on RowDataBound
Code: Using Client-Side - (which i recommend more)
Here you can set as many conditions to depend on your class values, no need to write extra server-side code
$(document).ready(function () {
$(".myGvClass").find("td").each(function () {
if ($(this).text() == "Class B") {
$(this).css("color", "Red");
}
if ($(this).text() == "Class A") {
$(this).css("color", "Blue");
}
if ($(this).text() == "Class C") {
$(this).css("color", "green");
}
// ..... and so on
});
HTML markup:
<asp:GridView ID="GridView1" runat="server" CssClass="myGvClass">
</asp:GridView>
CodeBehind:
GridView1.DataSource = YourDataTable;
GridView1.DataBind();
ScreenShot:
Code: Using serverside
Looping over Gridview rows at myGridview_DataBound event, and check condition cell value and set respective colors.
protected void myGridview_DataBound(object sender, EventArgs e)
{
for (int i = 0; i <= myGridview.Rows.Count - 1; i++)
{
string myClassVal = myGridview.Rows[i].Cells[2].Text;
if (myClassVal == "Class A")
{
myGridview.Rows[i].Cells[2].BackColor = Color.Green;
}
else if (myClassVal == "Class B")
{
myGridview.Rows[i].Cells[2].BackColor = Color.Red;
}
else
{
myGridview.Rows[i].Cells[2].BackColor = Color.Orange;
}
}
}
HTML :
<asp:GridView ID="myGridview" runat="server" ondatabound="myGridview_DataBound">
</asp:GridView>
Code Behind:
myGridview.DataSource = YourDataTable;
myGridview.DataBind();
ScreenShot:
Lots of ways to skin a cat, but if you really don't want to use RowDataBound, you could use a TemplateColumn containing a styled control in its ItemTemplate. E.g.
<asp:GridView ...>
...
<Columns>
...
<asp:TemplateField ...>
<ItemTemplate>
<asp:Panel ... CssClass='<%# GetStudentCssClass(Eval("student_Class")) %>'>
...
</asp:Panel>
</ItemTemplate>
...

gridview column value manipulated

my intention was to switch form an int-represented month value
(as it is in database table)
convert it (to display in GridView) as string(month name)
and return it back to database as int (covert back to original type, int-represented month).
these are the relevant elements in my GridView,
<asp:GridView ID="GV_DaysPerMonth" runat="server" DataSourceID="dsWorkDayPerMonth"
AutoGenerateColumns="False" DataKeyNames="recordID" AllowPaging="True"
CellPadding="4" ForeColor="#333333" GridLines="None" Font-Names="arial" PageSize="12"
OnRowDataBound="GV_DaysPerMonth_RowDataBound"
OnRowEditing="GV_DaysPerMonth_RowEditing"
OnRowUpdating="GV_DaysPerMonth_RowUpdating">
<AlternatingRowStyle BackColor="White" />
<Columns>
<asp:TemplateField HeaderText="חודש" ControlStyle-Width="100" HeaderStyle-Width="120" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<%# Eval("theMonth")%>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="TBX_theMonth" runat="server" Text='<%# Bind("theMonth")%>' />
</EditItemTemplate>
<asp:GridView ID="GV_DaysPerMonth" runat="server" DataSourceID="dsWorkDayPerMonth"
AutoGenerateColumns="False" DataKeyNames="recordID" AllowPaging="True"
CellPadding="4" ForeColor="#333333" GridLines="None" Font-Names="arial" PageSize="12"
OnRowDataBound="GV_DaysPerMonth_RowDataBound"
OnRowEditing="GV_DaysPerMonth_RowEditing"
OnRowUpdating="GV_DaysPerMonth_RowUpdating">
<AlternatingRowStyle BackColor="White" />
<Columns>
<asp:TemplateField HeaderText="Current Month" ControlStyle-Width="100" HeaderStyle-Width="120" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<%# Eval("theMonth")%>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="TBX_theMonth" runat="server" Text='<%# Bind("theMonth")%>' />
</EditItemTemplate>
i was tring using these Helper methods From code Behind
public static CultureInfo ILci = CultureInfo.CreateSpecificCulture("he-IL");
public static string GetMonthName(int mInt)
{
DateTime fullDate = new DateTime(2012, mInt, 2);
string[] tempDayArray = fullDate.ToString("MMMM", ILci).Split(' ');
return tempDayArray[0];
}
public static int GetMonthAsInt(string mStr)
{
return DateTime.ParseExact(mStr, "MMMM", ILci).Month;
to achieve this simple task but had few errors i would like to have an example to how is the right way to achieve it.
i thought it's simple cause displaying int via
<%# manipulation Function( Eval("columnName")) %>
would "just work"
but it got too complicated for me as newb
when trying it with Bind("columnName")
i was wrong by assuming the value was inside Cells[1] when it was actually in Cells[0]
so i do have it in normal mode
and also in Edit mode though not editble but via Label as in view mode instead of a TextBox
protected void GV_DaysPerMonth_RowDataBound(object sender, GridViewRowEventArgs e)
{
RowNum = GV_DaysPerMonth.Rows.Count;
GridViewRow CurRow = e.Row; // Retrieve the current row.
if (CurRow.RowType == DataControlRowType.DataRow)
{
bool isntEmptyMonth = string.IsNullOrEmpty(e.Row.Cells[0].Text) == false;
if (isntEmptyMonth)
{
e.Row.Cells[1].Text = RobCS.RDates.GetMonthName(Convert.ToInt32((e.Row.Cells[0].Text)));
}
}
}
so i think it might be the **missing handler for the edit mode** ?
This is what you would do to get a string Month name from an int:
CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(1);
More info here:
Best way to turn an integer into a month name in c#?
For converting month number into month name in sql server, look here:
Convert Month Number to Month Name Function in SQL
---- EDIT
OK, on RowDataBound, you would want to convert int to string, so it would be something like:
void CustomersGridView_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
// Display the month name. When you GridView is bound for the first time, you
// will bind the month number, which you can get in e.Row.Cells[1].Text. If
// Cells[1] does not work, try Cells[2], till you get the correct value. The
// convert the int to month name and assign it to the same Cell.
e.Row.Cells[1].Text = GetMonthNameFromInt(e.Row.Cells[1].Text)
}
}
On Row_updating, you want to convert the month name to int again, and then update you dataset (or save to the database)
protected void GridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
//Update the values.
GridViewRow row = GridView.Rows[e.RowIndex];
var monthName = ((TextBox)(row.Cells[1].Controls[0])).Text;
var monthNumber = GetMonthNumber(monthName);
// code to update your dataset or database with month number
//Reset the edit index.
GridView.EditIndex = -1;
//Bind data to the GridView control.
BindData();
}
Page class:
private static CultureInfo culture = CultureInfo.CreateSpecificCulture("he-IL");
public static string GetMonthName(string monthNum)
{
return culture.DateTimeFormat.GetMonthName(Convert.ToInt32(monthNum));
}
GridView:
<ItemTemplate>
<%# GetMonthName(Eval("theMonth").ToString())%>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="ddlMonth" runat="server" SelectedValue='<%# Bind("theMonth")%>'>
<asp:ListItem Value="1" Text="תשרי"></ListItem>
etc...
</asp:DropDownList>
</EditItemTemplate>
In your EditTemplate have a DropDownList with ListItems: value="1" Text="תשרי" etc.. so that it's the month number that's passed to your data layer for edits.

Gridview with Enable and Disable image buttons

I have gridview in an asp.net application. I want to insert a column with image buttons where by click on it will enable or disable users or change the status field in db and also change the image button image accordingly user status.
Meaning: I want to display different images for disabled and enabled users.
How can I do this in C# and bind the data to the image button?
Anyone please help. Thanks in advance.
Make use of the ItemDataBound event. This is where you can check each row of your grid and apply changes to it. Then you can hide / unhide or change buttons:
VB.net below but you can easily convert to C#:
Dim ib As ImageButton = CType(e.Item.FindControl("ibFav"), ImageButton)
ib.Visible = False
Dim ib2 As ImageButton = CType(e.Item.FindControl("ibRemFav"), ImageButton)
ib2.Visible = True
Sample User Model:
public class UserModel {
public string Name { get; set; }
public bool IsEnabled { get; set; }
}
Here is the GridView Code:
<asp:GridView ID="GridView" runat="server" AutoGenerateColumns="false"
onrowcommand="GridView_RowCommand" onrowdatabound="GridView_RowDataBound">
<Columns>
<asp:TemplateField>
<ItemStyle HorizontalAlign="Center" />
<ItemTemplate>
<asp:ImageButton ID="EnabledImgBtn" runat="server"
CommandArgument='<%# Eval("Name") %>'
CommandName="ResetUserState" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Name" HeaderText="Name" />
//Other columns....
</Columns>
</asp:GridView>
Set the 'CommandArgument' according to your needs. e.g the ID of the User.
Sample Code-behind for the gridview:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack){
LoadGridView();
}
}
private void LoadGridView()
{
this.GridView.DataSource = GetUsersFromDatabase();
this.GridView.DataBind();
}
protected void GridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var user = e.Row.DataItem as UserModel;
var enabledImgBtn = e.Row.FindControl("EnabledImgBtn") as ImageButton;
if (enabledImgBtn != null)
enabledImgBtn.ImageUrl = user.IsEnabled ? "~/YourImagePath/enabled.png"
: "~/YourImagePath/disalbed.png";
}
}
protected void GridView_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "ResetUserState")
{
if (e.CommandArgument!= null)
{
var userName = e.CommandArgument.ToString();
//Change user enabled state and Update database
//Sample code:
var user = FindUserByName("userName");
user.IsEnabled = !user.IsEnabled;
//SaveInDatabase(user);
LoadGridView();
}
}
}
You may consider using 'CommandField' with Type equal to 'Image' instead of 'TemplateField', but there is an issue with this approach, read more.
Hope this helps.
<asp:GridView ID="GridView" runat="server" AutoGenerateColumns="false"
onrowcommand="GridView_RowCommand" onrowdatabound="GridView_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="Change Status" ItemStyle-CssClass="GrdItemImg">
<ItemTemplate>
<asp:ImageButton ID="ibtnChangeActiveStatus" CommandArgument='<%#Eval("RecordID")%>'
CommandName='GRDSTATUS' runat="server" ImageUrl='<%# getStatusImage(Convert.ToInt32(DataBinder.Eval(Container.DataItem,"IsApproved"))) %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Col2" HeaderText="Col2" />
//Other Respective columns....
...........
..........
</Columns>
</asp:GridView>
And In CS file add the following function.
public string getStatusImage(int intStatus)
{
string strStatus = string.Empty;
if (intStatus == 1)
{
strStatus = "~/images/active.png";
}
else
{
strStatus = "~/images/inactive.png";
}
return strStatus;
}
So on the base of "intStatus" respective active / InActive Image will be set.

Get Business Object back from Grid View

What exactly is the e.Row.DataItem return.. MSDN says.. returns An Object that represents the underlying data object to which the GridViewRow object is bound.
Here is my DataGrid...
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="ObjectDataSource1" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:BoundField DataField="PracticeCode" HeaderText="PracticeCode" SortExpression="PracticeCode" />
<asp:BoundField DataField="AccountNo" HeaderText="AccountNo" SortExpression="AccountNo" />
<asp:BoundField DataField="PatientName" HeaderText="PatientName" SortExpression="PatientName" />
<asp:TemplateField HeaderText="Status">
<ItemTemplate>
<asp:Label ID="LblStatus" runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And I bind it with my Business Object List < Patient >.. In the row DataBound event, I try this...
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
Patient p1 = (Patient)e.Row.DataItem;
Label lbl = e.Row.FindControl("LblStatus") as Label;
if (p1 == null)
{
throw new Exception("P1 is null");
}
if (p1.OpenItems.Count > 0)
{
lbl.Text = "Has open Items";
}
else
{
lbl.Text = "";
}
}
I get the exception P1 is null... Why so... What am I missing..
Note : There could be other ways to accomplish this, but I'm looking especially why my p1 is null... and is there any way to get the Patient Object back from GridView after binding.
RowDataBound is called for the header and footer also, you need to make sure your currently in an actual DataRow before calling e.Row.DataItem:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType != DataControlRowType.DataRow)
return;
Patient p1 = (Patient)e.Row.DataItem;

Categories

Resources