static void

FileSizeFormatProvider

An ICustomFormatter for file sizes. See hack to get it working with DataGridView.

using System;
 
namespace Library.Forms
{
    /// <summary>
    /// Format a size in bytes to KB, MB or GB.
    /// </summary>
    /// <example><code>
    ///Debug.WriteLine(string.Format(new FileSizeFormatProvider(), "{0:2}", 10240)); //display 10.00KB
    ///Debug.WriteLine(string.Format(new FileSizeFormatProvider(), "{0:KB}", 1024)); //display 1KB
    ///Debug.WriteLine(string.Format(new FileSizeFormatProvider(), "{0:KB1}", 16245)); //display 15.9KB
    ///Debug.WriteLine(string.Format(new FileSizeFormatProvider(), "{0:MB1}", 102450)); //display 0.1MB
    ///Debug.WriteLine(string.Format(new FileSizeFormatProvider(), "{0:GB1}", 1073741824)); //display 1.0GB
    /// </code></example>
    public class FileSizeFormatProvider : IFormatProvider, ICustomFormatter
    {
        #region IFormatProvider Members
        public object GetFormat(Type formatType)
        {
            return (formatType == typeof(ICustomFormatter)) ? this : null;
        }
        #endregion
 
        #region ICustomFormatter Members
        public string Format(string format, object arg, IFormatProvider formatProvider)
        {
            string s = TryFormat(format, arg);
            if (!string.IsNullOrEmpty(s))
                return s; //we successfully formated
            //fall through to default formating http://msdn.microsoft.com/en-us/library/system.icustomformatter.format.aspx
            if (arg is IFormattable)
                s = ((IFormattable)arg).ToString(format, formatProvider);
            else if (arg != null)
                s = arg.ToString();
            return s;
        }
        #endregion
 
        private static string TryFormat(string format, object arg)
        {
            if (string.IsNullOrEmpty(format)) return null;
            if (!(format.StartsWith("KB", StringComparison.OrdinalIgnoreCase) ||
                format.StartsWith("MB", StringComparison.OrdinalIgnoreCase) ||
                format.StartsWith("GB", StringComparison.OrdinalIgnoreCase) ||
                format.StartsWith("FS", StringComparison.OrdinalIgnoreCase))) return null;
            //only on numeric types (FileInfo.Length is a long)
            if (!(arg is long || arg is decimal || arg is int)) return null;
 
            //try to convert to decimal
            decimal size;
            try
            {
                size = Convert.ToDecimal(arg);
            }
            catch (InvalidCastException)
            {
                size = 0;
            }
            //try to parse the decimal points
            int dps;
            if (format.Length > 2)
                int.TryParse(format.Substring(2), out dps);
            else
                int.TryParse(format, out dps);
 
            if (format.Length > 1)                //standardize
                format = format.Substring(0, 2).ToUpper(); //get first two chars
 
            const int KB = 1024;
            const int MB = KB * 1024;
            const int GB = MB * 1024;
            string suffix = "B";
 
            //if one of KB, MB or GB, divide, round and stringify
            switch (format)
            {
                case "KB":
                    size = size / KB;
                    suffix = "KB";
                    break;
                case "MB":
                    size = size / MB;
                    suffix = "MB";
                    break;
                case "GB":
                    size = size / GB;
                    suffix = "GB";
                    break;
                case "FS":
                    if (size >= GB)
                    {
                        size = size / GB;
                        suffix = "GB";
                    }
                    else if (size >= MB)
                    {
                        size = size / MB;
                        suffix = "MB";
                    }
                    else if (size >= KB)
                    {
                        size = size / KB;
                        suffix = "KB";
                    }
                    break;
            }
            return string.Format("{0:N" + dps + "}" + suffix, size);
        }
    }
}

DataGridView Hack

With DataGridViews you have to handle the CellFormatting event to force it to use your ICustomFormatter.

sizeCol.DefaultCellStyle.Format = "{0:KB1}";
sizeCol.DefaultCellStyle.FormatProvider = new FileSizeFormatProvider();
gv.CellFormatting += delegate(object sender, DataGridViewCellFormattingEventArgs e)
        {
            //because custom formatters aren't honoured
            DataGridView gv = (DataGridView)sender;
            DataGridViewColumn col = gv.Columns[e.ColumnIndex];
            if (col.DefaultCellStyle.FormatProvider is ICustomFormatter)
                e.Value = string.Format(col.DefaultCellStyle.FormatProvider, col.DefaultCellStyle.Format, e.Value);
        };