You will need to do the formatting yourself, but you can connect to the existing .NET formatting platform using the IFormatProvider and ICustomFormatter interfaces.
Here is one example of how to do this. A ConditionalFormatter class is created, consisting of several ConditionalFormat objects. The ConditionalFormat class has Predicate and a Format . ConditionalFormatter will look for all ConditionalFormat objects, sequentially defining the first where Predicate true, and use the associated Format . The formatter uses the letter "Z" as the format string.
class ConditionalFormat<T> where T : IFormattable { public Func<T, Boolean> Predicate { get; set; } public String Format { get; set; } public static readonly Func<T, Boolean> Tautology = _ => true; } class ConditionalFormatter<T> : Collection<ConditionalFormat<T>>, IFormatProvider, ICustomFormatter where T : IFormattable { public const String FormatString = "Z"; readonly CultureInfo cultureInfo; public ConditionalFormatter(IEnumerable<ConditionalFormat<T>> conditionalFormats) : this(conditionalFormats, null) { } public ConditionalFormatter(IEnumerable<ConditionalFormat<T>> conditionalFormats, CultureInfo cultureInfo) : base(conditionalFormats.ToList()) { this.cultureInfo = cultureInfo; } public Object GetFormat(Type formatType) { return formatType == typeof(ICustomFormatter) ? this : null; } public String Format(String format, Object arg, IFormatProvider formatProvider) { if (arg.GetType() != typeof(T)) return HandleOtherFormats(format, arg); var formatUpperCase = format.ToUpperInvariant(); if (formatUpperCase != FormatString) return HandleOtherFormats(format, arg); var value = (T) arg; foreach (var conditionalFormat in this) if (conditionalFormat.Predicate(value)) return ((IFormattable) value).ToString(conditionalFormat.Format, cultureInfo); throw new InvalidOperationException(String.Format("No format matching value {0}.", value)); } String HandleOtherFormats(String format, Object arg) { var formattable = arg as IFormattable; if (formattable != null) return formattable.ToString(format, this.cultureInfo); else if (arg != null) return arg.ToString(); else return String.Empty; } }
The class is generic and you will need to create an instance that matches the type you want to format. The following is an example of using Double :
var conditionalFormatter = new ConditionalFormatter<Double>( new[] { new ConditionalFormat<Double> { Predicate = d => -2 < d && d < 2, Format = "#,##0.00" }, new ConditionalFormat<Double> { Predicate = ConditionalFormat<Double>.Tautology, Format = "#,##0.0" }, } ); var value = 1234.5678; var formattedValue = String.Format(conditionalFormatter, "Value is {0:Z}", value);
source share