user3900520
user3900520

Reputation: 71

IValueConverter and Metric/Imperial units

I am planning to implement code that will use an IValueConverter to display units of measurement in either metric or imperial based on a boolean the user sets. The issue I am facing is that the data stored in my database is required to always be in metric. I'm using Entity Framework database first if that makes a difference.

So the situation I am wondering about is this: if a user has chosen to display data in imperial units, but then alters one of the fields, and saves it - how do I ensure that it is saved properly in metric? From what I've gathered by researching online it looks like that would be part of the converter's ConvertBack method? Right now I call Textbox.GetBindingExpression(TextBox.TextProperty).UpdateSource(); to save the data, and I don't understand how to make that work since, as I understand, it just grabs the value in the TextBox and saves it. Am I right, or if there is a ConvertBack method will that be called in order to get the TextProperty?

Also, generally speaking, am I going about this the correct way (i.e. using an IValueConverter to alter the display)? To be honest I am in way over my head on this project, but I have deadlines fast approaching, and have a dire need to do this right. Any help would be greatly appreciated.

Thanks.

Upvotes: 1

Views: 1465

Answers (1)

Evk
Evk

Reputation: 101453

So you have some model, and you want to edit some properties of that model using TextBox and ValueConverter. Let's take some dummy value converter, which will multiply value by 10, and in ConvertBack will divide value by 10

public class MyConverter : IValueConverter {
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
        if (value == null || value == DependencyProperty.UnsetValue)
            return null;
        return (decimal) value*10;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
        if (value == null || value == DependencyProperty.UnsetValue)
            return 0;
        decimal d;
        if (decimal.TryParse((string) value, out d))
            return d/10;
        return 0;
    }
}

Now some test model

public class MyModel : INotifyPropertyChanged {
    private decimal _someValue;

    public decimal SomeValue
    {
        get { return _someValue; }
        set
        {
            if (value == _someValue) return;
            _someValue = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

And then you have your textbox

<TextBox Width="150" Height="20" Text="{Binding SomeValue, Mode=TwoWay, Converter={StaticResource myConverter}, UpdateSourceTrigger=PropertyChanged}" />

If you use UpdateSourceTrigger=PropertyChanged, on each user edit, the value will be passed to your ConvertBack method, and the result will be assigned to SomeValue of your model.

When user presses save button, you just save your model to database using whichever method you have for that. You don't need to explicitly update properties of your model, because they are already up-to-date. You can also use UpdateSourceTrigger=LostFocus (default one). Then whenever field loses focus - property in your model will be synchronized with it (again, through ConvertBack)

Upvotes: 1

Related Questions