【问题标题】:Why Mvvm approach is not working for my Calculator?为什么 Mvvm 方法不适用于我的计算器?
【发布时间】:2014-09-27 11:52:03
【问题描述】:

我正在尝试使用 silverlight 5 处理 MVVM,我的 xaml 代码是这样的:

 <Grid x:Name="LayoutRoot" Background="White" Height="100" Width="350">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
       <TextBox Grid.Column="0" Text="{Binding FirstValue, Mode=TwoWay}" Height="25" TextAlignment="Right"/>
        <TextBlock Grid.Column="1" Text="+" Height="25" TextAlignment="Center"/>
        <TextBox Grid.Column="2" Text="{Binding SecondValue, Mode=TwoWay}" Height="25" TextAlignment="Right"/>
        <TextBlock Grid.Column="3" Text="=" Height="25" TextAlignment="Center"/>
        <TextBlock Grid.Column="4" Text="{Binding Result, Mode=OneWay}" Height="25" TextAlignment="Left"/>
        <Button Grid.Row="1" Grid.ColumnSpan="5" Margin="0,5,0,0" Content="Calculate" Command="{Binding CalculateCommand}"  />
    </Grid>

还有

public MainPage()
        {
            InitializeComponent();
            this.DataContext = new CalculatorViewModel();
        }

我的 CalculatorViewModel.cs 类是:

public class CalculatorViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public CalculatorModel cc;


        private string _firstValue;
        public string FirstValue
        {
            get { return _firstValue; }
            set
            {
                _firstValue = value;
                OnPropertyChanged("FirstValue");
            }
        }

        private string _secondValue;
        public string SecondValue
        {
            get { return _secondValue; }
            set
            {
                _secondValue = value;
                OnPropertyChanged("SecondValue");
            }
        }

        private string _result;
        public string Result
        {
            get { return _result; }
            private set
            {
                _result = value;
                OnPropertyChanged("Result");
            }
        }

        private ICommand _calculateCommand;
        public ICommand CalculateCommand
        {
            get { return _calculateCommand; }
        }

        public CalculatorViewModel()
        {
            cc = new CalculatorModel();
            cc.FirstValue = _firstValue;
            cc.SecondValue = _secondValue;
            cc.Result = _result;
            _calculateCommand = new RelayCommand(cc.Calculate) { IsEnabled = true };
            //This Calculate() is defined in Model class (CalculatorModel.cs).
         }    

        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
            }
        }

    }

我想在模型类(CalculatorModel.cs)中定义这个计算委托。根据我的理解,这就是模型类的意思。 (如果我错了请纠正我)。

我是这样做的:

 public class CalculatorModel
    {
        #region PROPERTIES
        public string FirstValue;
        public string SecondValue;
        public string Result;

        #endregion
        //CalculatorViewModel cv = new CalculatorViewModel();

        public CalculatorModel()
        {
            this.Result = "";
            this.FirstValue = "";
            this.SecondValue = "";              
        }
        public void Calculate()
        {
            MessageBox.Show("check : " +FirstValue);
            Result = (Convert.ToInt32(FirstValue) + Convert.ToInt32(SecondValue)).ToString();
        }
    }

问题是我不知道为什么在调试 Result 的值时,FirstValue 和 SecondValue 为 null 委托 calculate() 在按钮单击时被调用,但 Result 中没有更新输出。

有人可以纠正我在 Model 类中定义 calculate() 的方法有什么问题吗?

【问题讨论】:

    标签: c# .net silverlight mvvm data-binding


    【解决方案1】:

    您似乎没有更新模型中的值。数据绑定仅适用于 View 和 ViewModel。

        private string _firstValue;
        public string FirstValue
        {
            get { return _firstValue; }
            set
            {
                _firstValue = value;
                cc.FirstValue = _firstValue;     // add this
                OnPropertyChanged("FirstValue");
            }
        }
    

    并且对 SecondValue 也这样做。更改命令,以便将结果分配给 Result。

    这告诉您,您的设置不是最有效或最优雅的。 考虑

    1. 使模型 INotifyPropertyChanged 并绑定到 Model.FirstValue
    2. 或者,在此处放弃模型的概念。

    当您使模型实现 INPC 时,您可以(应该)从 VM 中完全删除 FirstValue、SecondValue 和 Result。您可以绑定到模型:Text="{Binding Path=cc.FirstValue, Mode=TwoWay}",然后将模型设为属性:

       public CalculatorModel cc { get; set; }   // must be a property
    

    否则,“重复”属性的更好模式是:

        //private string _firstValue;
        public string FirstValue
        {
            get { return cc.FirstValue; }
            set
            {
                //_firstValue = value;
                cc.FirstValue = value;           // add this
                OnPropertyChanged("FirstValue");
            }
        }
    

    避免两次存储数据。

    【讨论】:

    • 感谢您的回答,但现在在调试时,我可以看到文本框中写入的值可以访问,但结果尚未更新。任何想法为什么? (我已经对所有三个都进行了您建议的更改,我的意思是 Result 也是如此)
    • 你的意思是这个改变:private ICommand _calculateCommand;公共 ICommand CalculateCommand { get { return _calculateCommand; } 设置 { cc.Result = _result; } }
    • 不,这看起来不对。大致:new RelayCommand(() =&gt; Result = cc.Calculate())
    • 我需要更多帮助。通过您在回答中提出的两点,您的意思是说:ViewModel 类不适合拥有 INotifyPropertyChanged。必须在 Model 中完成?你能否在你的分析器中详细解释一下哪个类应该包含什么? (因为在许多示例中我没有在模型类中看到它们只是在 ViewModel 类中完成所有操作,所以我对此有点困惑)
    • 这是一个单独的问题,但要与cc = new CalculatorModel(); 一起跟踪逻辑。这叫相互恢复。
    猜你喜欢
    • 2015-05-31
    • 1970-01-01
    • 1970-01-01
    • 2020-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    相关资源
    最近更新 更多