我正在使用WPF和MVVM模式构建一个复利计算器。我的视图中有一个ComboBox,它允许用户选择复合间隔(例如“每日”、“每周”、“每月”等)。这个ComboBox的ItemsSource绑定到我的视图模型中的一个ObservableCollection属性,SelectedItem绑定到SelectedCompoundInterval属性。
当用户从ComboBox中进行选择时,我希望SelectedCompoundInterval属性的值也会相应地更新。但是,当我在视图模型中调用Calculate方法(该方法使用此属性作为计算的输入)时,SelectedCompoundInterval属性的值始终为空。
MyViewModel类
namespace CompoundInterestCalculator
{
internal class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private Calculations _calculations = new Calculations();
private bool _showResults;
private decimal _initialAmount;
public decimal InitialAmount
{
get { return _initialAmount; }
set
{
_initialAmount = value;
Debug.WriteLine(_initialAmount.ToString());
OnPropertyChanged(nameof(InitialAmount));
}
}
private decimal _interestRate;
public decimal InterestRate
{
get { return _interestRate; }
set
{
_interestRate = value;
OnPropertyChanged(nameof(InterestRate));
}
}
private int _years;
public int Years
{
get { return _years; }
set
{
_years = value;
OnPropertyChanged(nameof(Years));
}
}
private int _months;
public int Months
{
get { return _months; }
set
{
_months = value;
OnPropertyChanged(nameof(Months));
}
}
public ObservableCollection<string> CompoundIntervals { get; } = new ObservableCollection<string>
{
"Daily","Weekly", "Monthly", "Quarterly", "Yearly"
};
private string _selectedCompoundInterval;
public string SelectedCompoundInterval
{
get { return _selectedCompoundInterval; }
set
{
if (_selectedCompoundInterval != value)
{
_selectedCompoundInterval = value;
OnPropertyChanged(nameof(SelectedCompoundInterval));
Debug.WriteLine("SelectedCompoundInterval changed: " + value);
}
}
}
public ObservableCollection<string> InterestRateTypes { get; } = new ObservableCollection<string>
{
"Percent", "Decimal"
};
private string _selectedInterestRateType;
public string SelectedInterestRateType
{
get { return _selectedInterestRateType; }
set
{
_selectedInterestRateType = value;
OnPropertyChanged(nameof(SelectedInterestRateType));
}
}
public DataTemplate CurrentTemplate
{
get
{
if (_showResults)
return (DataTemplate)Application.Current.FindResource("ResultsTemplate");
else
return (DataTemplate)Application.Current.FindResource("InputTemplate");
}
}
public void Calculate()
{
Debug.WriteLine("CompoundIntervals: " + string.Join(", ", CompoundIntervals));
Debug.WriteLine("SelectedCompoundInterval: " + SelectedCompoundInterval);
// Perform calculations here
decimal initialAmount = InitialAmount;
decimal interestRate = InterestRate;
int years = Years;
int months = Months;
string compoundInterval = SelectedCompoundInterval;
Debug.WriteLine("compoundInterval: " + compoundInterval);
string interestRateType = SelectedInterestRateType;
decimal totalAmount = _calculations.CalculationsAmounts(initialAmount, interestRate, years, months, compoundInterval, interestRateType);
// Show results
_showResults = true;
OnPropertyChanged(nameof(CurrentTemplate));
}
}
}
字符串
计算类
namespace CompoundInterestCalculator
{
internal class Calculations
{
public decimal CalculationsAmounts(decimal initialAmount, decimal interestRate, int years, int months, string compoundInterval, string interestRateType)
{
Debug.WriteLine("compoundInterval: " + compoundInterval);
int compoundFrequency;
switch (compoundInterval)
{
case "Daily":
compoundFrequency = 365;
break;
case "Weekly":
compoundFrequency = 52;
break;
case "Monthly":
compoundFrequency = 12;
break;
case "Quarterly":
compoundFrequency = 4;
break;
case "Yearly":
compoundFrequency = 1;
break;
default:
throw new ArgumentException("Invalid compound interval");
}
if (interestRateType == "Percent")
{
interestRate /= 100;
}
decimal totalAmount = initialAmount * (decimal)Math.Pow((double)(1 + interestRate / compoundFrequency), years * compoundFrequency + months * (compoundFrequency / 12));
return totalAmount;
}
}
}
型
MainWindow.xaml.cs代码
namespace CompoundInterestCalculator
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private MyViewModel _myViewModel;
public MainWindow()
{
InitializeComponent();
DataContext = new MyViewModel();
_myViewModel = new MyViewModel();
}
private void CalculateButton_Click(object sender, RoutedEventArgs e)
{
MyContentControl.ContentTemplate = (DataTemplate)FindResource("ResultsTemplate");
_myViewModel.Calculate();
}
private void BackButton_Click(object sender, RoutedEventArgs e)
{
MyContentControl.ContentTemplate = (DataTemplate)FindResource("InputTemplate");
}
private void NumericOnly(object sender, TextCompositionEventArgs e)
{
e.Handled = IsTextNumeric(e.Text);
}
private static bool IsTextNumeric(string str)
{
System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex("[^0-9]");
return reg.IsMatch(str);
}
private void NumericDecimalOnly(object sender, TextCompositionEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox != null)
{
string newText = textBox.Text.Insert(textBox.CaretIndex, e.Text);
decimal value;
if (!decimal.TryParse(newText, out value) || value < 0.01m || value > 99.9999999m)
{
e.Handled = true;
}
}
}
private void NumericMonthlyOnly(object sender, TextCompositionEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox != null)
{
string newText = textBox.Text.Insert(textBox.CaretIndex, e.Text);
int value;
if (!int.TryParse(newText, out value) || value < 1 || value > 12)
{
e.Handled = true;
}
}
}
}
}
型
xaml组合框代码
<ComboBox Grid.Column="1" ItemsSource="{Binding CompoundIntervals}" SelectedItem="{Binding SelectedCompoundInterval, Mode=TwoWay}" Margin="10,5,0,0" Width="100" Height="20">
</ComboBox>
型
我试着在多个地方调试程序,我注意到ObservableCollection正确地填充了组合框,并且在调试SelectedCompoundInterval属性时,它确实会在每次我在程序中更改它时通知我计算中使用的compoundInterval字符串应该有一些东西要存储。
我假设这意味着问题在这一点和我计算之间的某个地方,因为在我的计算代码中调试compoundInterval字符串总是显示Null值,然后switch语句抛出argumentException,因为它不适合任何Null值的情况。
1条答案
按热度按时间pexxcrt21#
初始化ViewModel示例出错:
字符串
但我建议在XAML中初始化示例。这将使在Visual Studio设计器中创建布局更加容易。
可能的变体之一: