简体   繁体   中英

How to display temperature in user chosen units

I have a WPF application that saves user defined temperature values in Celsius in the model. These are entered in TextBoxes with numeric masks, which are bound to integer properties on the VM.

I would like to allow the user to be able to enter the temperature in either Celsius or Fahrenheit. This is controlled by a simple User setting. The value must therefore also be displayed in the correct unit in the textbox.

I've tried using a converter, but I'm not having much success. I can get the converter to work, but not how I want to.

When the UserControl loads, the value might need to be converted from Celsius to Fahrenheit. I was able to get this working using this converter:

    public class CelciusToFahrenheit : IValueConverter
    {
        /// <summary>
        /// Converts from Celsius to Fahrenheit if required by user settings
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            double returnValue = System.Convert.ToInt32(value);

            if (Settings.Default.FahrenheitFlag)
            {
                returnValue = (returnValue * 1.8) + 32;
            }

            return Math.Floor(returnValue);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            int returnValue = System.Convert.ToInt32(value);

            if (Settings.Default.FahrenheitFlag)
            {
                returnValue = System.Convert.ToInt32((returnValue - 32) / 1.8);
            }

            return returnValue;
        }
    }

The problem here is that this also converts the value when the user is typing the value in. This means that if you try to type 66, you end up with 77 due to the rounding error.

Has anyone done this before? I'm sure it's possible, but I've been banging my head against this for a while now.

I would do the calculation in a view model that can be bound to two text boxes. One for Celsius, one for Fahrenheit. If the user enters text in the Celsius text box, the Fahrenheit value is calculated and inserted into the Fahrenheit text box and vice versa. No need to change a setting for this.

public class TemperatureViewModel: INotifyPropertyChanged
{
    private double _celsius;
    public double Celsius
    {
        get { return _celsius; }
        set {
            if (value != _celsius) {
                _celsius = value;
                _fahrenheit = Math.Round(1.8 * value + 32.0, 2);
                OnPropertyChanged(nameof(Celsius));
                OnPropertyChanged(nameof(Fahrenheit));
            }
        }
    }

    private double _fahrenheit = 32.0;
    public double Fahrenheit
    {
        get { return _fahrenheit; }
        set {
            if (value != _fahrenheit) {
                _fahrenheit = value;
                _celsius = Math.Round((value - 32.0) / 1.8, 2);
                OnPropertyChanged(nameof(Fahrenheit));
                OnPropertyChanged(nameof(Celsius));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Note that the VM implements INotifyPropertyChanged to tell the UI when the values change. The effect is that the text boxes refresh automatically. Note also the the property setters assign the calculated value to the backing field, not to the property, to avoid the two properties to update each other in a vicious cycle.

My implementation rounds the calculated temperatures to 2 fractional digits. But you can change this of course.

I don't believe this is where you should be doing your conversion. Your Model has a temperature property, which as you say is always stored as Celsius. And that's the way it should stay.

There are no need for value converters here, but probably want to move this calculation in to your ViewModel, and have the get and set properties determine what conversion has to happen based on the user settings, and avoid the value-converter all together.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM