我在Prism / WPF项目中有这样的ViewModel类。
public class ContentViewModel : ViewModelBase, IContentViewModel
{
public ContentViewModel(IPersonService personService)
{
Person = personService.GetPerson();
SaveCommand = new DelegateCommand(Save, CanSave);
}
public Person Person { get; set; }
public DelegateCommand SaveCommand { get; set; }
private void Save()
{
// Save actions here...
}
private bool CanSave()
{
return Person.Error == null;
}
}
上述ViewModel中使用的人员类型定义如下:
public class Person : INotifyPropertyChanged, IDataErrorInfo
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
OnPropertyChanged("FirstName");
}
}
// other properties are implemented in the same way as above...
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private string _error;
public string Error
{
get
{
return _error;
}
}
public string this[string columnName]
{
get
{
_error = null;
switch (columnName)
{
// logic here to validate columns...
}
return _error;
}
}
}
ContentViewModel的实例设置为View的DataContext。在View中我使用了绑定到Person,如下所示:
<TextBox Text="{Binding Person.FirstName, ValidatesOnDataErrors=True}" />
<Button Content="Save" Command="{Binding SaveCommand}" />
当我对TextBox进行更改时绑定到Person的属性(如FirstName)并单击Save我可以在ViewModel命令处理程序中看到更改。但是,如果这些属性中的任何一个在验证中失败,则永远不会执行CanSave并且永远不会禁用按钮
如何在上述场景中禁用基于DelegateCommand的CanExecute操作处理程序的按钮?
答案 0 :(得分:4)
在ContentViewModel的构造函数中添加此行
public ContentViewModel(IPersonService personService)
{
//GetPerson
Person.PropertyChanged +=person_PropertyChanged;
}
并编写一个方法来处理您调用CommandManager.InvalidateRequerySuggested()或SaveCommand.RaiseCanExecuteChanged()
的事件private void person_PropertyChanged(object sender, EventArgs args)
{
CommandManager.InvalidateRequerySuggested();
//SaveCommand.RaiseCanExecuteChanged()
}
希望这有效。 : - )
答案 1 :(得分:2)
尝试使用可以更改错误的所有属性:
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
OnPropertyChanged("FirstName");
OnPropertyChanged("Error");
}
}
可选地
switch (columnName)
{
// logic here to validate columns...
OnPropertyChanged("Error");
}
您遇到的问题是错误更改时未调用OnPropertyChanged。
下一步是在创建person时订阅person的propertychanged事件,并创建一个检查propertychanged的处理程序,然后更改命令使用的boolean变量。
public ContentViewModel(IPersonService personService)
{
Person = personService.GetPerson();
Person.PropertyChanged+= PersonPropertyChangedHandler;
SaveCommand = new DelegateCommand(Save, personHasError);
}
bool personHasError = false;
void PersonPropertyChangedHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "Error")
{
if(Person.Error == null)
personHasError = true;
else
personHasError = false;
}
}
希望这有效。我手工制作并没有检查它,所以让我知道它的马车或其他什么并且不正确的
答案 2 :(得分:1)
简而言之 - 如果您认为可以更改yourDelegateCommand.RaiseCanExecuteChanged()
返回值,则应致电CanExecute()
。
在您的示例中,您应该通过INotifyPropertyChanged
界面通知您的Person.Error
媒体资源已更改,订阅Person.PropertyChanged
课程中的ContentViewModel
个事件并致电{{1}每次更改SaveCommand.RaiseCanExecuteChanged()
时。请注意 - 在您的情况下Person.Error
不会自动重新计算,例如Person.Error
更改时 - 您应该手动执行此操作。
<强>更新:强>
Person.FirstName
如果您还要将public class ContentViewModel : ViewModelBase, IContentViewModel
{
public ContentViewModel(IPersonService personService)
{
Person = personService.GetPerson();
Person.PropertyChanged += Person_PropertyChanged;
SaveCommand = new DelegateCommand(Save, CanSave);
}
private void PersonPropertyChangedHandler(object sender, PropertyChangedEventArgs e)
{
SaveCommand.RaiseCanExecuteChanged();
}
private void Save()
{
// Save actions here...
}
private bool CanSave()
{
return IsErrorPresented(Person);
}
private bool IsErrorPresented(object o)
{
if (!(o is IDataErrorInfo))
return false;
var propNames = o.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Select(p => p.Name);
var o2 = (o as IDataErrorInfo);
var errors = propNames.Select(p => o2[p])
.Where(p => !String.IsNullOrEmpty(p))
.ToList();
ValidationSummary.ErrorMessages = errors;
return errors.Count > 0;
}
}
<TextBox Text="{Binding Person.FirstName,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True,
ValidatesOnExceptions=True,
NotifyOnValidationError=True}" />
<Button Content="Save" Command="{Binding SaveCommand}" />
指定为PropertyChanged
,您的保存按钮会在您输入时更新。