Custom Formatting in a SPGridView

One of the problems with the SPGridView occurs, if you display e.g. the file size of files, and try to sort with this information. The internal value you get from a SPFile of FileInfo Object shows you the length of the file in bytes. This is great if you want to sort this column. But what if you choose to display the long value with the amount of bytes for a file not as the value, but formatted with SPUtility.FormatSize(file.length)?

Well, you cannot sort for this column anymore, because sorting System.string values is not the same as sorting the original file size which is a System.long.

So what can you do to a) format the file size nicely and b) still be able to sort your entries with their file sizes?

  1. Create a new class with a custom format method
    • Add a DataColumn to your DataTable
      _DataTable.Columns.Add(“Size”, typeof(FileSize));
      • Create a BoundField and add it to your SPGridView

        • Add a new DataRow to your DataTable
          row[“Size”] = new FileSize(file.Length);
If you look at my FileSize class you will notice that I am overriding the .ToString() method with a PadLeft. This is due to the fact that a string sorting is not the same as sorting a long. But if you put zeros in front of the long and then sort the resulting string, you will get the desired sorting.

The big TODO with this solution is, that you have to disable the filtering for the “Size” column. This is due to the fact that we use our own class in the DataTable, which does not work with the FilteredDataSourcePropertyFormat = “{1} LIKE ‘{0}’" from the SPGridView, because it is not a string. “System.Data.EvaluateException: Cannot perform ‘Like’ operation on RH.FileLink and System.String

new class

 1: class FileSize : IFormattable

<span class=lnum>   2:  </span>{
 3:  private readonly long _Value;
<span class=lnum>   4:  </span> 
 5:  public long Value
<span class=lnum>   6:  </span>    {
 7:  get { return _Value; }
<span class=lnum>   8:  </span>    }
<span class=lnum>  10:  </span>    <span class=kwrd>public</span> FileSize(<span class=kwrd>long</span> <span class=kwrd>value</span>)
 11:  {
<span class=lnum>  12:  </span>        _Value = <span class=kwrd>value</span>;
 13:  }
<span class=lnum>  14:  </span> 
 15:  public override string ToString()
<span class=lnum>  16:  </span>    {
 17:  //fill trailing zeros to be able to sort the size correctly
<span class=lnum>  18:  </span>        <span class=kwrd>string</span> <span class=kwrd>value</span> = _Value.ToString().PadLeft(12);
 19:  return value;
<span class=lnum>  20:  </span>    }
<span class=lnum>  22:  </span>    <span class=rem>// Write a custom Format method which shows the filesize "nicely"</span>
 23:  public string ToString(string format, IFormatProvider fp)
<span class=lnum>  24:  </span>    {
 25:  if (format.Equals("nice"))
<span class=lnum>  26:  </span>            <span class=kwrd>return</span> SPUtility.FormatSize(_Value);
 27:  else 
<span class=lnum>  28:  </span>            <span class=kwrd>return</span> _Value.ToString(format, fp);
 29:  }
<span class=lnum>  30:  </span>}


 1: BoundField size = new BoundField();
<span class=lnum>   2:  </span>size.DataField = <span class=str>"Size"</span>;
 3: size.HtmlEncode = false;
<span class=lnum>   4:  </span>size.HeaderText = <span class=str>"Size"</span>;
 5: size.SortExpression = "Size";
<span class=lnum>   6:  </span><span class=rem>// use custom formatting, to display 1Kb instead of 1024</span>
 7: size.DataFormatString = "{0:nice}";
<span class=lnum>   8:  </span> 
 9: _GridView.Columns.Add(size);

Update 24. March 2009

Filtering can be adjusted by changing the “FilteredDataSourcePropertyFormat” property to “{1}='{0}’";
Thanks to Volker for this one.
Technorati Tags: ,,