Click here to Skip to main content
15,895,256 members
Articles / Desktop Programming / WPF

Unit Conversions in C#/WPF

Rate me:
Please Sign up or sign in to vote.
4.70/5 (22 votes)
30 Oct 2008CPOL11 min read 71.1K   1.6K   39  
On keeping measurement unit in sync and properly bound to UI.
using System;
using System.Collections.Generic;
using System.ComponentModel;

namespace UnitsConversion
{
  internal class Units : INotifyPropertyChanged
  {

    internal readonly Unit DegreesCelcius;
    internal readonly Unit DegreesFahrenheit;
    private Unit temperatureSystemUnit;
    private IList<Unit> temperatureUnits;
    private Unit temperatureUserUnit;



    private Units()
    {
      TemperatureUnits = new[]
      {
        DegreesCelcius = new Unit("Degrees Celcius", "�C", 1.0, 0.0, UnitType.Temperature),
        DegreesFahrenheit = new Unit("Degrees Fahrenheit", "�F", 1.8, 32, UnitType.Temperature)
      };
      // example
      TemperatureSystemUnit = DegreesCelcius;
      TemperatureUserUnit = DegreesFahrenheit;
    }



    public static Units Instance
    {
      get
      {
        return UnitsCreator.instance;
      }
    }

    public Unit TemperatureSystemUnit
    {
      get { return temperatureSystemUnit; }
      set
      {
        temperatureSystemUnit = value;
        Changed("TemperatureSystemUnit");
      }
    }

    public IList<Unit> TemperatureUnits
    {
      get { return temperatureUnits; }
      set { temperatureUnits = value; }
    }

    public Unit TemperatureUserUnit
    {
      get { return temperatureUserUnit; }
      set
      {
        temperatureUserUnit = value;
        Changed("TemperatureUserUnit");
      }
    }




    public event PropertyChangedEventHandler PropertyChanged;





    internal void Changed(string name)
    {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler != null)
      {
        handler(this, new PropertyChangedEventArgs(name));
      }
    }

    internal static double Convert(Unit from, Unit to, double value)
    {
      if (from.Type != to.Type)
        throw new InvalidOperationException("Conversion between incompatible types.");
      if (from.Shift == to.Shift && from.Scale == to.Scale)
        return value;

      double v = (value - from.Shift) / from.Scale;
      return v * to.Scale + to.Shift;   
    }

    internal double ConvertFromSystem(UnitType type, double value)
    {
      switch (type)
      {
        case UnitType.Temperature:
          return Convert(TemperatureSystemUnit, TemperatureUserUnit, value);
        default:
          throw new InvalidOperationException("Unit type not supported.");
      }
    }

    internal double ConvertToSystem(UnitType type, double value)
    {
      switch (type)
      {
        case UnitType.Temperature:
          return Convert(TemperatureUserUnit, TemperatureSystemUnit, value);
        default:
          throw new InvalidOperationException("Unit type not supported.");
      }
    }





    private class UnitsCreator
    {
      internal static readonly Units instance = new Units();
      static UnitsCreator() { /* required */ }
    }

    internal struct Unit
    {

      internal string Abbreviation;
      internal string Name;
      internal double Scale;
      internal double Shift;
      internal UnitType Type;



      public override string ToString()
      {
        return string.Format("{0} ({1})",
                             Name, Abbreviation);
      }

      internal Unit(string name, string abbreviation, 
        double scale, double shift, UnitType type)
      {
        if (scale == 0.0)
          throw new ArgumentException("Scale factor cannot be zero.");

        Name = name;
        Abbreviation = abbreviation;
        Scale = scale;
        Shift = shift;
        Type = type;
      }
    }
  }

  internal enum UnitType
  {
    Temperature,
    Length
  }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Founder ActiveMesa
United Kingdom United Kingdom
I work primarily with the .NET technology stack, and specialize in accelerated code production via code generation (static or dynamic), aspect-oriented programming, MDA, domain-specific languages and anything else that gets products out the door faster. My languages of choice are C# and C++, though I'm open to suggestions.

Comments and Discussions