I am fairly new to C# and I'm teaching myself WPF in the process. I can't seem to find a solution for my problem after hours of searching. I have a demo app I'm writing that accepts input values on 3 fields. If data is input in one field, the other fields
should be calculated and updated. The user should be able to input numeric values in any of the 3 fields and the other fields will be calculated.
Furthermore, I'm using IDataErrorInfo for validation and using binding in MVVM, WPF application. The code somewhat works, but has an issue with input since the fields can also be calculated. IE, when I input data in the view, its value gets changed due to
the calculations. Also, if I key something with a decimal in it, it gets even worse, often not even accepting the decimal, or accepting a 0 after a decimal, such as 1.056, which stops at 1.0. It appears the problem is with the indexer, but I don't know C#,
MVVM, and binding well enough to know how to fix it, and I'm only just now learning how IDataErrorInfo works specifically, the indexer.
Below is the code, which will successfully execute, but exhibit the problems listed above. However, the view is not entirely completed as I have yet to bind a textbox for the IDataErrorInfo error messages. Any advice would be appreciated.
View - MainWindow.xaml
<Window x:Class="NumberConverterforWin.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:NumberConverterforWin"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Title="Number Converter 1.0" Height="150" Width="350"><Grid Margin="0,0,0,0"><Grid.Background><SolidColorBrush Color="{DynamicResource {x:Static SystemColors.MenuHighlightColorKey}}"/></Grid.Background><Grid.RowDefinitions><RowDefinition Height="33*"/><RowDefinition Height="33*"/><RowDefinition Height="33*"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="33*"/><ColumnDefinition Width="33*"/><ColumnDefinition Width="33*"/></Grid.ColumnDefinitions><TextBlock
x:Name="multiplier1text"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="0,0,0,0"
TextWrapping="Wrap"
Text="Multiplier 1"
FontWeight="Bold"
/><TextBlock
x:Name="differencetext"
Margin="10,0"
TextWrapping="Wrap"
Text="Difference"
Grid.Row="1"
FontWeight="Bold"
HorizontalAlignment="Center"
TextAlignment="Center"
VerticalAlignment="Center"
/><TextBlock
x:Name="multiplier2text"
Margin="0"
TextWrapping="Wrap"
Text="Multiplier 2"
VerticalAlignment="Center"
Grid.Row="2"
FontWeight="Bold"
HorizontalAlignment="Center"
TextAlignment="Center"
/><TextBox
x:Name="multiplier1"
Grid.Column="1"
HorizontalAlignment="Center"
Margin="10,9"
Text="{Binding Path=Multiplier1, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
VerticalAlignment="Center"
Width="90"
VerticalContentAlignment="Center"
MaxLines="1"
/><TextBox
x:Name="difference"
Grid.Column="1"
HorizontalAlignment="Center"
Margin="10,9"
Grid.Row="1"
Text="{Binding Path=Difference, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
VerticalAlignment="Center"
Width="90"
VerticalContentAlignment="Center"
MaxLines="1"
/><TextBox
x:Name="multiplier2"
Grid.Column="1"
HorizontalAlignment="Center"
Margin="10,9"
Grid.Row="2"
Text="{Binding Path=Multiplier2, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
VerticalAlignment="Center"
Width="90"
VerticalContentAlignment="Center"
MaxLines="1"
/></Grid></Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace NumberConverterforWin
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Model initial = new Model(0, 100, 0);
base.DataContext = new Converter(initial);
}
}
}
ViewModel - converter.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
namespace NumberConverterforWin
{
public class Converter : INotifyPropertyChanged, IDataErrorInfo
{
readonly Model _model;
string _multiplier1Text;
string _differenceText;
string _multiplier2Text;
string _propertyText;
public Converter(Model model)
{
_model = model;
_multiplier1Text = model.Multiplier1.ToString();
_differenceText = model.Difference.ToString();
_multiplier2Text = model.Multiplier2.ToString();
}
public string Multiplier1
{
get
{
return _multiplier1Text;
}
set
{
if (value == _multiplier1Text)
return;
_multiplier1Text = value;
this.OnPropertyChanged("Multiplier1");
}
}
public string Difference
{
get
{
return _differenceText;
}
set
{
if (value == _differenceText)
return;
_differenceText = value;
this.OnPropertyChanged("Difference");
}
}
public string Multiplier2
{
get
{
return _multiplier2Text;
}
set
{
if (value == _multiplier2Text)
return;
_multiplier2Text = value;
this.OnPropertyChanged("Multiplier2");
}
}
#region IDataErrorInfo Members
public string Error
{
get { return _model.Error; }
}
public string this[string propertyName]
{
get
{
double propertyvalue;
string msg;
double _factor;
switch (propertyName)
{
case "Multiplier1":
_propertyText = _multiplier1Text;
msg = this.Validate(propertyName, out propertyvalue);
if (!String.IsNullOrEmpty(msg))
return msg;
_model.Multiplier1 = propertyvalue;
_factor = propertyvalue * 70;
_model.Difference = Math.Round(100 - _factor, 4);
_model.Multiplier2 = Math.Round(_factor / 40, 4);
break;
case "Difference":
_propertyText = _differenceText;
msg = this.Validate(propertyName, out propertyvalue);
if (!String.IsNullOrEmpty(msg))
return msg;
_model.Difference = propertyvalue;
_factor = 100 - propertyvalue;
_model.Multiplier1 = Math.Round(_factor / 70, 4);
_model.Multiplier2 = Math.Round(_factor / 40, 4);
break;
case "Multiplier2":
_propertyText = _multiplier2Text;
msg = this.Validate(propertyName, out propertyvalue);
if (!String.IsNullOrEmpty(msg))
return msg;
_model.Multiplier2 = propertyvalue;
_factor = propertyvalue * 40;
_model.Multiplier1 = Math.Round(_factor / 70, 4);
_model.Difference = Math.Round(100 - _factor, 4);
break;
}
Difference = _model.Difference.ToString();
Multiplier2 = _model.Multiplier2.ToString();
Multiplier1 = _model.Multiplier1.ToString();
return _model[propertyName];
}
}
string Validate(string propertyname, out double propertyvalue)
{
propertyvalue = -1;
string msg = null;
if (String.IsNullOrEmpty(_propertyText))
msg = propertyname + " is missing.";
if (!Double.TryParse(_propertyText, out propertyvalue))
msg = propertyname + " is not a numeric value.";
return msg;
}
#endregion // IDataErrorInfo Members
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion // INotifyPropertyChanged Members
}
}
Model - model.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
namespace NumberConverterforWin
{
public class Model : IDataErrorInfo
{
public Model(double multiplier1, double difference, double multiplier2)
{
this.Multiplier1 = multiplier1;
this.Difference = difference;
this.Multiplier2 = multiplier2;
}
public double Multiplier1 { get; set; }
public double Difference { get; set; }
public double Multiplier2 { get; set; }
#region IDataErrorInfo Members
public string Error
{
get { return null; }
}
public string this[string propertyName]
{
get
{
if (propertyName == "Multiplier1")
{
if (this.Multiplier1 < 0)
return "Multiplier1 cannot be less than 0.";
if (1.4286 < this.Multiplier1)
return "Multiplier 1 cannot be greater than 1.4286.";
}
if (propertyName == "Difference")
{
if (this.Difference < 0)
return "Difference cannot be less than 0.";
if (100 < this.Multiplier1)
return "Difference cannot be greater than 100.";
}
if (propertyName == "Multiplier2")
{
if (this.Multiplier2 < 0)
return "Multiplier 2 cannot be less than 0.";
if (2.5 < this.Multiplier2)
return "Multiplier 2 cannot be greater than 2.5.";
}
return null;
}
}
#endregion // IDataErrorInfo Members
}
}