当模型的属性发生变化时,如何触发ViewModel的CanExecute方法?
How to trigger CanExecute method of ViewModel when a property of the Model changes?
我的问题是如何从模型中触发 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));
}
}
}
}
编辑以澄清: 仅 使以下示例按预期工作的事情是 提高 PropertyChanged
模型上的事件 属性 并使用框架的 CommandBinding。所有剩余的代码绝对只是为了“有东西要展示”并将模型与视图模型逻辑分开。
请考虑我为您整理的这个演示(使用 MVVM Light Libs 所以我不必自己实现 INotifyPropertyChanged)。
启动程序后,您应该会在左侧看到一个包含两个条目的 ListView。单击一个到 select 个并在右侧“编辑”它。
注意以下行为:
- ViewModel 将拒绝在性别框中输入除“男性”、“女性”、“多样化”和“未知”以外的任何其他值
- ListView 中的“性别”列不会更新,因为 ViewModel 不会引发 PropertyChanged 事件
- 最重要的是:在性别框中输入“未知”,按钮将立即禁用,反之亦然
我所做的只是实现了一个“愚蠢的”模型(没有业务逻辑)和一个“愚蠢的”ViewModel(将 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 事件(这符合您的场景,即从属 属性“属于不同的 class” ).
框架负责重新检查依赖项所需的更新。它叫做“魔法”
有一些方法可以“强制”重新查询 like here 但如果您觉得有必要这样做,那么恕我直言,您的设计有问题。
收获框架的力量 - 即使这意味着您的项目启动速度较慢,因为您必须学习和重新认识事物。这是简单的方法 - 相信我。
我的问题是如何从模型中触发 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));
}
}
}
}
编辑以澄清: 仅 使以下示例按预期工作的事情是 提高 PropertyChanged
模型上的事件 属性 并使用框架的 CommandBinding。所有剩余的代码绝对只是为了“有东西要展示”并将模型与视图模型逻辑分开。
请考虑我为您整理的这个演示(使用 MVVM Light Libs 所以我不必自己实现 INotifyPropertyChanged)。
启动程序后,您应该会在左侧看到一个包含两个条目的 ListView。单击一个到 select 个并在右侧“编辑”它。
注意以下行为:
- ViewModel 将拒绝在性别框中输入除“男性”、“女性”、“多样化”和“未知”以外的任何其他值
- ListView 中的“性别”列不会更新,因为 ViewModel 不会引发 PropertyChanged 事件
- 最重要的是:在性别框中输入“未知”,按钮将立即禁用,反之亦然
我所做的只是实现了一个“愚蠢的”模型(没有业务逻辑)和一个“愚蠢的”ViewModel(将 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 事件(这符合您的场景,即从属 属性“属于不同的 class” ).
框架负责重新检查依赖项所需的更新。它叫做“魔法”
有一些方法可以“强制”重新查询 like here 但如果您觉得有必要这样做,那么恕我直言,您的设计有问题。
收获框架的力量 - 即使这意味着您的项目启动速度较慢,因为您必须学习和重新认识事物。这是简单的方法 - 相信我。