Gaz83
Gaz83

Reputation: 2885

Property change on one control to refresh converter on another?

I have a page when a user can enter their weight. The data is always store as lbs because most of my calculations in the app are base on lbs. But, visually the user can enter kg, lbs and stone.

So for the example of my question lets say we have the following classes.

int UnitType
double Weight

Now, Lets say I have a page which has a ComboBox with the SelectedIndex bound to UnitType. The ComboBox has 3 items "lbs", "kg" and "st". Under that there is textbox which you can enter a value. This will be bound to Weight and will have a converter.

Say the user selects "lbs" and enters 200 but then decides to change from lbs to kg. My question is how would I get the section changed event of the ComboBox to trigger a refresh of the textbox converter?

In my head I'm guessing I would have to do something like this

private int _unitType;
public int UnitType
{
   get { return _unitType;}
   set 
   { 
     _unitType = value;
     NotifyPropertyChanged("UnitType");
     NotifyPropertyChanged("Weight");
   }
 }

private double _weight;
public double Weight
{
   get { return _weight;}
   set 
   { 
     _weight= value;
     NotifyPropertyChanged("Weight");
   }
 }

Would this work or is there something else I can do, maybe in the binding itself?

Upvotes: 0

Views: 1011

Answers (2)

cvraman
cvraman

Reputation: 1697

One possible way where you could implement this is given below :
a. Here we are using a factor variable to store relative values of weights. We are storing the relative value in the constructor.
b. 1 Pound = 0.453592 Kg = 0.0714286f Stone.
c. The conversion of weight is done set property in the Selected Weight Type

            private WeightType _selectedWeightType;
            public WeightType SelectedWeightType
            {
                get { return _selectedWeightType; }
                set
                {
                    var previousType = _selectedWeightType;
                    _selectedWeightType = value;
                    NotifyPropertyChanged("SelectedWeightType");
                    if(previousType != null)
                        CurrentWeight = (CurrentWeight / previousType.Factor) * _selectedWeightType.Factor;
                }
            }

The complete code is given below:
XAML:

<Window x:Class="TestWPFApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestWPFApp"
        Title="MainWindow" Height="350" Width="525">

    <Grid>
        <StackPanel Orientation="Vertical" VerticalAlignment="Center">
            <ComboBox Width="100" Height="20" ItemsSource="{Binding WeightTypeList}" DisplayMemberPath="UnitType" SelectedIndex="0" SelectedItem="{Binding SelectedWeightType}">
            </ComboBox>
            <TextBox Width="100" Height="20" Text="{Binding CurrentWeight,Mode=TwoWay}"></TextBox>
        </StackPanel>
    </Grid>
</Window>

Code Behind:

using System.Windows;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System;
using System.ComponentModel;
using System.Windows.Data;
using System.Globalization;
namespace TestWPFApp
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new MainViewModel();
        }
    }

    public class WeightType : INotifyPropertyChanged
    {
        private int _id;
        public int Id
        {
            get { return _id; }
            set
            {
                _id = value;
                NotifyPropertyChanged("Id");
            }
        }

        private string _unitType;
        public string UnitType
        {
            get { return _unitType; }
            set
            {
                _unitType = value;
                NotifyPropertyChanged("UnitType");
            }
        }

        private float _factor;
        public float Factor
        {
            get { return _factor; }
            set
            {
                _factor = value;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        /// <summary>
        /// Call this to force the UI to refresh it's bindings.
        /// </summary>
        /// <param name="name"></param>
        public void NotifyPropertyChanged(String name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }

    public class MainViewModel : INotifyPropertyChanged
    {
        private List<WeightType> _weightTypeList = new List<WeightType>();
        public List<WeightType> WeightTypeList
        {
            get { return _weightTypeList; }
            set
            {
                _weightTypeList = value;
            }
        }
        private double _currentWeight;
        public double CurrentWeight
        {

            get { return _currentWeight; }
            set
            {
                _currentWeight = value;
                NotifyPropertyChanged("CurrentWeight");
            }
        }

        private WeightType _selectedWeightType;
        public WeightType SelectedWeightType
        {
            get { return _selectedWeightType; }
            set
            {
                var previousType = _selectedWeightType;
                _selectedWeightType = value;
                NotifyPropertyChanged("SelectedWeightType");
                if(previousType != null)
                    CurrentWeight = (CurrentWeight / previousType.Factor) * _selectedWeightType.Factor;
            }
        }

        public MainViewModel()
        {
            WeightTypeList.Add(new WeightType() { Id = 1, UnitType = "Lbs", Factor = 1f });
            WeightTypeList.Add(new WeightType() { Id = 2, UnitType = "Kg",Factor = 0.453592f });
            WeightTypeList.Add(new WeightType() { Id = 1, UnitType = "St", Factor = 0.0714286f });
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged(String name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }

    public class BoolToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType,
            object parameter, CultureInfo culture)
        {
            return null;
        }

        public object ConvertBack(object value, Type targetType,
            object parameter, CultureInfo culture)
        {
            return null;
        }
    }

}

Upvotes: 2

Luis Filipe
Luis Filipe

Reputation: 8718

  • You can have a calculated property that knows how to convert and display the weight in the selected system. You'd call NotifyPropertyChanged("CalculatedWeight") on both sets of UnitType and Weight.

  • Alternatively, i would use your approach. Have a converter in the binding of the Weight property and put the logic there.

  • Even a better choice would be to create a user control that has the combobox and the textbox, create a class "WeightProvider" and bind the userControl datacontext to that class and then you have two choices:

    1. The class has the calculated property
    2. The user control has the converter itself

    it's the most effective way if you are to have more pages with weights.

Upvotes: 1

Related Questions