首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用DelegateCommand的CanExecute操作

使用DelegateCommand的CanExecute操作
EN

Stack Overflow用户
提问于 2012-03-11 17:40:30
回答 3查看 6.6K关注 0票数 2

我在一个Prism / WPF项目中有一个类似这样的ViewModel类。

代码语言:javascript
复制
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中使用的person类型定义如下:

代码语言:javascript
复制
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的一个实例被设置为视图的DataContext。在视图中,我使用了绑定到Person,如下所示:

代码语言:javascript
复制
<TextBox Text="{Binding Person.FirstName, ValidatesOnDataErrors=True}" />
<Button Content="Save" Command="{Binding SaveCommand}" />

当我对绑定到Person的属性(如FirstName )的TextBox进行更改并单击Save时,我可以在ViewModel命令处理程序中看到更改。但是,如果这些属性中的任何一个在验证中失败,CanSave就永远不会执行,按钮也永远不会被禁用。

在上述场景中,如何根据DelegateCommand的CanExecute操作处理程序禁用按钮?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-03-15 13:44:18

尝试对所有可以更改的属性执行以下操作:

代码语言:javascript
复制
 public string FirstName
{
    get { return _firstName; }
    set
    {
        _firstName = value;
        OnPropertyChanged("FirstName");

        OnPropertyChanged("Error");
    }
}

另一个选择

代码语言:javascript
复制
        switch (columnName)
        {
            // logic here to validate columns...

            OnPropertyChanged("Error");
        }

您遇到的问题是,当错误发生变化时,OnPropertyChanged不会被调用。

下一步是在创建person的属性changes事件时订阅它,并创建一个处理程序来检查属性changes,然后更改命令使用的布尔变量。

代码语言:javascript
复制
 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;
    } 
}

希望这能起作用。我手工构建了这个,没有检查它,所以让我知道它是否有buggy或其他什么,我会纠正它

票数 2
EN

Stack Overflow用户

发布于 2012-03-14 17:36:37

在ContentViewModel的构造函数中添加以下行

代码语言:javascript
复制
public ContentViewModel(IPersonService personService)
{
    //GetPerson
    Person.PropertyChanged +=person_PropertyChanged;
}

并编写一个方法来处理调用CommandManager.InvalidateRequerySuggested()或SaveCommand.RaiseCanExecuteChanged()的事件

代码语言:javascript
复制
private void person_PropertyChanged(object sender, EventArgs args)
{
   CommandManager.InvalidateRequerySuggested();
   //SaveCommand.RaiseCanExecuteChanged()
}

希望这能起作用。:-)

票数 4
EN

Stack Overflow用户

发布于 2012-03-11 18:09:25

简而言之,当你认为你的CanExecute()返回值可以改变的时候,你应该调用yourDelegateCommand.RaiseCanExecuteChanged()

在您示例中,您应该通过INotifyPropertyChanged接口通知您的Person.Error属性已更改,订阅ContentViewModel类中的Person.PropertyChanged事件,并在每次更改Person.Error时调用SaveCommand.RaiseCanExecuteChanged()。请小心-在您的场景中,例如,当Person.FirstName发生更改时,Person.Error不会自动重新计算-您应该手动执行此操作。

更新:

代码语言:javascript
复制
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指定为UpdateSourceTrigger,则在键入过程中将更新保存按钮。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9653874

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档