1

我的问题是如何从模型中触发 ViewModel 方法。

我正在使用 MVVM 开发 WPF 应用程序。所以我有一个按钮,,SubmitMedPrescCommand(使用中继命令实现)和一个SelectedMedPrescRepeat绑定到模型的组合框()。当用户选择下拉菜单时,会在模型的属性中引发 PropertyChange 事件,但我需要调用 CanExecute(在 ViewModel 中)才能启用按钮。

下面列出了我的代码示例。任何帮助,将不胜感激 !提前致谢 !

视图模型是这样的:

public class EpCreateMedicineViewModel : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    public ICommand SubmitMedPrescCommand { get; set; }
    
    public EpCreateMedicineViewModel()
    {
        SubmitMedPrescCommand = new RelayCommand<MedicinePrescriptionForSubmission>(ExecuteSubmitMedPrescCommand, CanExecuteSubmitMedPrescCommand);
    }
    
    private MedicinePrescriptionForSubmission _medicinePrescForSubm;
    public MedicinePrescriptionForSubmission MedicinePrescForSubm
    {
        get { return _medicinePrescForSubm; }
        set
        {
            if (value != this._medicinePrescForSubm)
            {
                this._medicinePrescForSubm = value;
                OnPropertyRaised("MedicinePrescForSubm");
            }
        }
    }
        
    public bool CanExecuteSubmitMedPrescCommand(object parameter)
    {
        if (_medicinePrescForSubm.MedicineForSubmGeneralInfo.SelectedMedPrescRepeat!=null)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

以及属性所属的模型:

public class MedicinePrescriptionForSubmission
{
    public MedicineForSubmGeneralInfo MedicineForSubmGeneralInfo { get; set; }
    
    public class MedicineForSubmGeneralInfo : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        
        private MedicinePrescriptionRepeat _selectedMedPrescRepeat; // THE PROPERTY THAT THE COMBOBOX IS BINDED TO
        public MedicinePrescriptionRepeat SelectedMedPrescRepeat
        {
            get { return _selectedMedPrescRepeat; }
            set
            {
                _selectedMedPrescRepeat = value;
                OnPropertyRaised("SelectedMedPrescRepeat");
                //CanExecuteSubmitMedPrescCommand(_selectedMedPrescRepeat); // THE METHOD OF THE VIEWMODEL THAT I WANT TO BE TRIGERRED WHEN MedicinePrescriptionRepeat changes
            }
        }
        private void OnPropertyRaised(string propertyname)
        {
            PropertyChangedEventHandler handle = PropertyChanged;
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
            }
        }
    }
}
4

1 回答 1

0

编辑澄清:使以下示例按预期工作的唯一方法是引发PropertyChanged模型属性上的事件并使用框架的 CommandBinding。所有剩余的代码都是绝对的,只是为了“展示一些东西”并将模型与视图模型逻辑分开。

请考虑我为您准备的这个演示(使用MVVM Light Libs,因此我不必自己实现 INotifyPropertyChanged)。

Github 上的 CanExecute 示例

启动程序后,您应该会在左侧看到一个 ListView,其中包含两个条目。单击一个以选择一个并在右侧“编辑”它。

演示应用

请注意以下行为:

  • 在性别框中输入的除“男性”、“女性”、“多样化”和“未知”之外的任何其他值都将被 ViewModel 拒绝
  • ListView 中的“性别”列不会更新,因为 ViewModel不会引发 PropertyChanged 事件
  • 最重要的是:在性别框中输入“未知”,按钮将立即禁用,反之亦然

禁用按钮

我所做的只是实现了一个“愚蠢的”模型(没有业务逻辑)和一个“愚蠢的”视图模型(将 int 值转换为字符串,反之亦然)。然后我实现了绑定到按钮的命令,如下所示:

    public ICommand DisplayGenderValueCommand { get { return new RelayCommand(this.DisplayGenderValueExecute, this.DisplayGenderValueCanExecute); } }

    private void DisplayGenderValueExecute()
    {
        MessageBox.Show($"Gender {this.Gender} has a model value of {this._MyModel.Gender}");
    }

    private bool DisplayGenderValueCanExecute()
    {
        return this._MyModel.Gender > 0;
    }

ViewModel 中的属性什么都不做,只是更新模型:

    public string Gender
    {
        get
        {
            if (_MyModel.Gender == 0) { return "unknown"; }
            if (_MyModel.Gender == 1) { return "female"; }
            if (_MyModel.Gender == 2) { return "male"; }
            if (_MyModel.Gender == 3) { return "diverse"; }
            return "error";
        }
        set
        {
            if (value == "unknown") _MyModel.Gender = 0;
            if (value == "female") _MyModel.Gender = 1;
            if (value == "male") _MyModel.Gender = 2;
            if (value == "diverse") _MyModel.Gender = 3;
        }
    }

虽然只有模型引发 PropertyChanged 事件(这与您的依赖属性“属于不同类”的场景一致)。

框架负责重新检查依赖项所需的更新。它被称为“魔法”

有一些方法可以像这里一样“强制”重新查询,但是如果您觉得有必要这样做,那么恕我直言,您的设计有问题。

收获框架的力量——即使这意味着您的项目启动速度较慢,因为您必须学习和重新审视事物。这是最简单的方法——相信我。

于 2020-11-26T06:26:53.487 回答