Click here to Skip to main content
15,885,366 members
Articles / Desktop Programming / WPF
Tip/Trick

WPF SmartPrecisionConverter

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
19 Jan 2017CPOL2 min read 8.9K   1   2
A value converter that allows smart rounding for text display

Introduction

In many WPF applications that display data, you could be dealing with a large variety of data. Numerical values in the same grid can be in the millions and in fractions. In that case, rounding the number simply isn't enough because if there is 1,234,567.894, it's likely the decimal precision is completely meaningless; however, if I have .0000894 and I round to three decimal places, I could be losing all of the data.

It's possible to use scientific notation, but scientfic notation can make it very difficult to compare values. Additionally, scientific notation tends to be a very poor display format for .01 to 1,000 which may cover a good amount of the data to be displayed.

The SmartPrecisionConverter simply applies an algorithm to round based on the number. In the case of large numbers, there's no decimals and in the case of small numbers, you specified number of non-zero digits.

Using the Code

Here are some examples of the expected output:

  • 1,234.5678 with 3 non-zero significant digits auto adjusted should be 1,234
  • 234.5678 with 3 non-zero significant digits auto adjusted should be 234
  • 34.5678 with 3 non-zero significant digits auto adjusted should be 34.6
  • .0005678 with 3 non-zero significant digits auto adjusted should be .000568

Below is the complete code for the converter...

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace NSanity.Wpf.Core.Converters
{
    [ValueConversion(typeof(object), typeof(string))]
    public class SmartPrecisionConverter : IValueConverter
    {
        private const double SignificantNonZeroDigits = 3;

        /// <summary>
        /// Converts a numerical value to a rounded value with a configured or 
        /// algorithm applied number of non-zero digits.
        /// </summary>
        /// <param name="value">The numerical value.</param>
        /// <param name="targetType">Hopefully a string.</param>
        /// <param name="parameter">NULL for no formatting.  Double.NaN for auto. 
        /// Or the specified number of decimal places.</param>
        /// <param name="culture">Yes please.</param>
        /// <returns>A formatted numerical value.</returns>
        public object Convert(object value, Type targetType, object parameter, 
                              System.Globalization.CultureInfo culture)
        {
            try
            {
                if (parameter != null)
                {
                    double digits = Double.Parse(parameter.ToString());
                    double number = Double.Parse(value.ToString());

                    if (digits.Equals(Double.NaN) && Math.Abs(number) < 
                                    Math.Pow(10, SignificantNonZeroDigits) && number != 0)
                    {
                        return Math.Round(number, (int)Math.Floor
                                     (SignificantNonZeroDigits - Math.Log10(Math.Abs(number))));
                    }
                    else if (digits.Equals(Double.NaN) && Math.Abs(number) >= 
                                      Math.Pow(10, SignificantNonZeroDigits))
                    {
                        return Math.Round(number, 0);
                    }
                    else if (!digits.Equals(Double.NaN))
                    {
                        return Math.Round(number, (int)digits);
                    }
                }

                return value;
            }
            catch
            {
                return value;
            }
        }

        public object ConvertBack(object value, Type targetType, 
                object parameter, System.Globalization.CultureInfo culture)
        {
            // Converting back could be very dangerous because of loss of precision - so don't do it.
            throw new NotImplementedException();
        }
    }
}

Because I'm writing this as a tip/trick, I don't intend to include a sample project - for now anyway.

Part of the reason why this handles fixed digit formatting as well is so you can have settings and/or menu item selection to dynamically adjust precision.

Points of Interest

Couple notable items with the implementation:

  • The value is passed as an object and converted by parsing its string conversion. Rather inefficient but allows the greatest flexibility for data types this could support.
  • I do catch all exceptions and return the original value in many of my converters just in case there's something unexpected the UI doesn't come crumbling down, but obviously you may want to throw this or handle it differently.

History

  • 2017-01-19: Initial revision

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United States United States
More than fourteen years of experience programming with six years of WPF application development. Dedicated business application developer with large focus on performance tuning for multithreaded applications. Experience developing for small scale applications and large scale distributed systems at senior and architect levels. Experience developing for a wide range of industry applications to include artificial lift, baggage tracking, distribution, customer relation management, and commodities.

Comments and Discussions

 
QuestionSample use cases? Pin
PeejayAdams20-Jan-17 3:48
PeejayAdams20-Jan-17 3:48 
AnswerRe: Sample use cases? Pin
PureNsanity20-Jan-17 7:01
professionalPureNsanity20-Jan-17 7:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.