I am auto generating columns in gridview depending on search parameters, few columns will be added or removed.
Please suggest me a way to set the date format to dd-mmm-yyyy
for entire column in gridview.
For now, I'm doing it using rowdatabound
. It checks every row, So it takes time to show the results.
This is what I do in rowdatabound
if (e.Row.RowType == DataControlRowType.DataRow)
{
System.Data.DataRowView dtview;
DateTime dt;
int intCounter;
dtview = (DataRowView)e.Row.DataItem;
for (intCounter = 0; intCounter <= dtview.Row.ItemArray.Length - 1; intCounter++)
{
if (dtview.Row.ItemArray[intCounter] is System.DateTime)
{
dt = (DateTime)dtview.Row.ItemArray[intCounter];
e.Row.Cells[intCounter].Text = dt.ToString("dd-MMM-yyyy");
}
}
}
This checks for all records and then changes based on condition.
But I want to do it better, just by identifying the column and change the date format for complete column.
Disclaimer: I haven't tried this myself, but it looks possible.
A GridView
has a public property called ColumnsGenerator
that has a type of IAutoFieldGenerator
. This is the object that determines how the columns are generated.
There's already an implementation of IAutoFieldGenerator
out there, the default one: GridViewColumnsGenerator
. This is a public, non-sealed class, and you can derive a type from it.
The method you would have to override is this one:
public override List<AutoGeneratedField> CreateAutoGeneratedFields(
object dataObject, Control control);
Note the output, a List<T> of AutoGeneratedField
. AutoGeneratedField
has a property called DataFormatString
:
public override string DataFormatString { get; set; }
So all you'd have to do is override CreateAutoGeneratedFields
, like this:
public class MyDerivedGridViewColumnsGenerator : GridViewColumnsGenerator
{
public override List<AutoGeneratedField> CreateAutoGeneratedFields(
object dataObject, Control control)
{
var list = base.CreatedAutoGeneratedFields(dataObject, control);
foreach(var field in list)
{
if(field.DataType == typeof(DateTime))
field.DataFormatString = "dd-MMM-yyyy";
}
return list;
}
}
Now, I'm not clear on how the ColumnsGenerator
property gets set, so you might have to do it in code. But that should be fairly simple, since GridViewColumnsGenerator
has a parameterless constructor:
// GridView myGridView;
myGridView.ColumnsGenerator = new MyDerivedGridViewColumnsGenerator();
I would set it before you bind to the GridView
, so it's in place when it's time to create the columns.
I'm a little late. But this worked for me. It still uses the RowDataBound() method. But it only runs against the first row in the data source.
protected void gvGridView_RowDataBound(Object sender, GridViewRowEventArgs e)
{
DataRowView drv = (DataRowView)e.Row.DataItem;
if (e.Row.RowType == DataControlRowType.DataRow)
{
for (int i = 0; i < ct_columns; i++)
{
DataControlFieldCell dcf = e.Row.Cells[i] as DataControlFieldCell;
/* default date format: hide 'time' values */
if (e.Row.RowIndex == 0
&& (dcf.ContainingField.GetType().Name == "BoundField" // defined columns
|| dcf.ContainingField.GetType().Name == "AutoGeneratedField")) // auto-generated columns
{
BoundField bf = dcf.ContainingField as BoundField;
if (bf != null && String.IsNullOrEmpty(bf.DataFormatString))
{
string col_name = bf.DataField;
if (!String.IsNullOrEmpty(col_name) && drv[col_name] != null)
{
if (drv[col_name].GetType().Name == "DateTime")
{
// set format for first row
string date = drv[col_name].ToString();
if (!String.IsNullOrEmpty(date))
dcf.Text = DateTime.Parse(date).ToShortDateString();
// set format for other rows
bf.DataFormatString = "{0:M/dd/yyyy}";
}
}
}
}
}
}
}
if you are binding an DataTable to Grid then Write an extension method or link Query like
public static void ChangeDateFormat<T>(this DataColumn column, Func<object, T> conversion)
{
foreach(DataRow row in column.Table.Rows)
{
row[column] = conversion(row[column]);
}
}
And to call that Method
dataTable.Columns["DateColumanName"].ChangeDateFormat(
val => DateTime.Parse(val.ToString()).ToString("dd/MMM/yyyy"));
Actual Source code pulled from here
And also note you need check the existence of column and data type and the other checks to get rid of errors.
Hope it helps.
Here's a fairly simple solution: rather than handle each row separately, set-up the columns before binding the grid.
In the following example, view
is an object that generates a regular DataTable
and the grid view has its AutoGenerateColumns
property set to false
.
Essentially, you just examine the columns' data type and when its a DateTime
, set the format you want.
DataTable dt = view.GetReport();
Type dateType = typeof(DateTime);
foreach (DataColumn column in dt.Columns)
{
BoundField f = new BoundField();
f.HeaderText = column.ColumnName;
f.DataField = column.ColumnName;
if(column.DataType == dateType)
f.DataFormatString = "{0:d}"; // Or whatever
gvReport.Columns.Add(f);
}
gvReport.DataSource = dt;
gvReport.DataBind();
I managed to format the values of an auto generated datetime column implementing the event ColumnAdded of the DataGridView:
private void dataGridView_ColumnAdded(object sender, DataGridViewColumnEventArgs e)
{
if (e.Column.ValueType == typeof(DateTime))
{
e.Column.DefaultCellStyle.Format = "dd-MMM-yyyy";
}
}
Use Eval
function to define string formation in aspx code:
<% # Eval("Date", "{0:dd-MMM-yyyy}") %>
Complete Example:
<asp:TemplateField HeaderText="Date">
<ItemTemplate>
<% # Eval("Date", "{0:dd-MMM-yyyy}") %>
</ItemTemplate>
</asp:TemplateField>