1

I am trying to format my Gridview columns to display decimal values upto 2 places after the decimal point. I am aware of both DataFormatString='{0:0.00} for the boundfield and also Eval("NumFailedFiles", "{0:0.00}") for ItemTemplate.

But i want this to be configurable, i.e. i want to get the no. of decimal places from the database and apply to the boundfield or itemtemplate. For acheiving this i have tried formatting in gridview_RowDataBound Event but in vain.

 GridDecimal = Convert.ToInt32(resXResourceSet.GetString("GridMaxDecimals"));
        var field = gridView.Columns[1] as BoundField;
        field.DataFormatString = "{0:0.00}";

With this code i am encountering an exception which says

"Object reference not set to an instance of an object"

at the 3rd line of the above code.

Can someone help me on how to achieve this for both boundfield and Itemtemplate

This is my datasource to clear the ambiguity

My data source:

croxy
  • 3,641
  • 8
  • 25
  • 42
Shekar.gvr
  • 1,374
  • 2
  • 13
  • 37
  • [What is a `NullReferenceException` and how do I fix it?](http://stackoverflow.com/q/4660142/447156) – Soner Gönül Dec 16 '15 at 11:42
  • What is `GridDecimal` and what is the `DataSource` of the `GridView`? – Tim Schmelter Dec 16 '15 at 11:44
  • @timschmelter GridDecimal is just an integer variable, which i am assigning a value by hitting the database. It indicates on how many decimal places should be displayed in the gridview. – Shekar.gvr Dec 17 '15 at 05:40

2 Answers2

3

You could use the DataBound event which is triggered once after the grid was databound. For example (depends on the actual datasource of your grid):

protected void GridView_DataBound(Object sender, EventArgs e)
{
    GridView grid = (GridView)sender;
    BoundField col = (BoundField)grid.Columns[1];
    int numDecimals = 2; // from database
    col.DataFormatString = "{0:N" + numDecimals + "}";
}

If you have a TemplateField use RowDataBound, you should use a lazy-load property like following to avoid that the value has to be loaded for every row:

private int? _NumDecimals;
private int NumDecimals 
{
    get 
    {
        if (!_NumDecimals.HasValue)
            _NumDecimals = GetNumDecimalsFromDB();
        return _NumDecimals.Value;
    }
    set 
    {
        _NumDecimals = value;
    }
}

protected void GridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // if following doesnt work use the debugger to see the type of e.Row.DataItem
        DataRow row = ((DataRowView)e.Row.DataItem).Row;
        int numFailedFiles = row.Field<int>("NumFailedFiles");
        //presuming that your TemplateField contains a Label with ID="LblNumFailedFiles"
        Label LblNumFailedFiles = (Label)e.Row.FindControl("LblNumFailedFiles");
        string formatString = String.Format("N{0}", NumDecimals);
        LblNumFailedFiles.Text = numFailedFiles.ToString(formatString);
    }
}
Tim Schmelter
  • 411,418
  • 61
  • 614
  • 859
  • Thanks for the help @Tim, that seems to be working for boundfield, how about the ItemTemplate? how do i do the same with the TemplateField. As TemplateField doesnt have DataFormatString Property. I am aware that from html in the .aspx we can set the format right after the Eval or Bind function seperated by comma, but how to acheive that from C# – Shekar.gvr Dec 17 '15 at 05:52
  • @Shekar.gvr: then you have to use `RowDataBound`, i will provide an example. – Tim Schmelter Dec 17 '15 at 08:58
  • I am getting an exception 'specified cast is not valid' at line number 2 of your code i.e. int numFailedFiles=row.Field("NumfailedFiles"); @Tim – Shekar.gvr Dec 17 '15 at 09:53
  • I have assumed the NumFaliedFields as the DataSource Column name and replaced NumFailedfields with 'Scannedmpins'. Here is my aspx code snippet @Tim – Shekar.gvr Dec 17 '15 at 09:54
  • @Shekar.gvr: so what is the type of that column? You just have to evaluate `row.Table.Columns["NumfailedFiles"].DataType` in the debugger and use that type in `row.Field`. – Tim Schmelter Dec 17 '15 at 09:58
  • Yes, i got your point. And now it is working . Thanks a lot @Tim – Shekar.gvr Dec 17 '15 at 10:09
  • @Shekar.gvr: you're welcome. Just a side-note: you should initialize a field variable `NumDecimals` where you `DataBind` the `GridView`. Then use that variable in `RowDataBound`. On that way you only need to load this value from database once instead of for every row of the `GridView`(since `RowDataBound` is triggered for every row). In my example i use a method `GetNumDecimals`. This could be a lazy-loading property, so one that checks if the variable is initialized. If it is it can be returned otherwise it needs to be loaded from database, – Tim Schmelter Dec 17 '15 at 10:24
  • Can i do this with the devexpress grid as well ? if yes, can you help me out with an example @Tim – Shekar.gvr Dec 17 '15 at 11:02
  • @Shekar.gvr: i'm not familiar with devexpress grids but why should it not work, have you tried it? – Tim Schmelter Dec 17 '15 at 11:15
  • Yes, I have tried it, a devex grid has a edittemplate class which has a property called displayformat. dxgrid.edittemplate.displayformat="{0:N0}"; this doesn't work for me. @Tim – Shekar.gvr Dec 19 '15 at 08:16
  • Hi Tim, for the boundfield, when I am trying to set the dataformatstring to Decimal format as you have mentioned above I find that it is not working at all, neither is an exception being thrown.Your thoughts please? – Shekar.gvr Dec 23 '15 at 09:48
0

OnRowDataBound of GridView you have to determine which row type you want to custom like header row, data row, and so on. and also RowDataBound event is raised for every row so you need to access specific row with specific column not gridview .

Solutions 1: If Boundfield is binded with data

  protected void GridView_RowDataBound(Object sender, GridViewRowEventArgs e)
  {
    if(e.Row.RowType == DataControlRowType.DataRow)
    {
      // Fetching BoundField Value.
      double dbvalue =Convert.ToDouble(e.Row.Cells[ColumnNumber].Text);
      e.Row.Cells[ColumnNumber].Text = String.Format("{0:0.00}",dbvalue  );
      Label lblnum = (Label)e.Row.Cells[ColumnNumber].FindControl("labelID");
      lblnum.Text =  String.Format("{0:0.00}", integervaluetoformat);
    }
  }

Solutions 2: (If the Column is a Item Field Template)

In case of ItemTemplate Field no need to fire RowDataBound:

<asp:TemplateField>
    <ItemTemplate>
       <asp:Label ID="lblnum" runat="server" Text='<%# String.IsNullOrEmpty(Eval("dbcolumn").ToString()) ?  "" :  string.Format("{0:0.00}",Convert.ToDouble(Eval("dbcolumn").ToString())) %>'></asp:Label>
    </ItemTemplate>
 </asp:TemplateField>
Rojalin Sahoo
  • 997
  • 1
  • 6
  • 18
  • i am sure this will work , but i want it to be done from code behind(aspx.cs). And the format {0:0.00} is not fixed. It may change depending on the database value. Eg: for one column it may be 2 decimals and for another it may be 4 – Shekar.gvr Dec 17 '15 at 06:09