使用DelegateCommand的CanExecute操作

时间:2012-03-11 09:40:30

标签: wpf mvvm prism delegatecommand

我在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操作处理程序的按钮?

3 个答案:

答案 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,您的保存按钮会在您输入时更新。