XAML 未将ComboBox中的选定值传递给WPF MVVM应用程序中的方法

oug3syen  于 2023-08-01  发布在  其他
关注(0)|答案(1)|浏览(75)

我正在使用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值的情况。

pexxcrt2

pexxcrt21#

初始化ViewModel示例出错:

public partial class MainWindow : Window
    {
        private readonly MyViewModel _myViewModel;
        public MainWindow()
        {
            InitializeComponent();

            // The field and the DataContext must have the same instance.
            _myViewModel = new MyViewModel();
            DataContext = _myViewModel;           
        }

字符串
但我建议在XAML中初始化示例。这将使在Visual Studio设计器中创建布局更加容易。
可能的变体之一:

<Window.DataContext>
        <local:MyViewModel/>
    </Window.DataContext>
public partial class MainWindow : Window
    {
        private readonly MyViewModel _myViewModel;
        public MainWindow()
        {
            InitializeComponent();

            _myViewModel = (MyViewModel) DataContext;           
        }

相关问题