具有输入验证的WPF命令绑定-如何启用“保存"功能.仅当所有输入均有效时才按 [英] WPF command binding with input validation - how to enable the "save" button only if all input is valid

查看:88
本文介绍了具有输入验证的WPF命令绑定-如何启用“保存"功能.仅当所有输入均有效时才按的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的ViewModel中,我实现了IDataErrorInfo接口(以及INotifyPropertyChanged).输入验证按预期工作,我在那里没有问题.

In my ViewModel I have implemented IDataErrorInfo interface (along with INotifyPropertyChanged). Input validation works as intended, I have no problems there.

我将此属性作为IDataErrorInfo public string Error { get { return this[null]; } }的一部分,据我了解,如果所有经过验证的输入均通过验证,Error应为空,因此我将此作为我的CanExecute方法传递

I have this property as part of IDataErrorInfo public string Error { get { return this[null]; } } To my understanding, Error should be empty if all validated inputs pass validation, so I pass this as my CanExecute method

return !string.IsNullOrEmpty(Error);

但是,我的保存"按钮从未启用.我的猜测是CanExecuteChanged永远不会被触发.如果是这样,我应该在哪里以及如何触发它?

But, my "save" button never gets enabled. My gues is that CanExecuteChanged never gets trigered. If that's true, where and how should I trigger it?

这是我的RelayCommand类.我尝试了其他实现方式,但结果是相同的.我认为它可行,因为如果不将CanExecute方法传递给构造函数,则会启用保存"按钮.

This is my RelayCommand class. I have tried other ways of implementation, but the results were the same. I think it works, because the "save" button is enabled if I don't pass CanExecute method to the constructor.

public class RelayCommand : ICommand
{
    private readonly Action execute;
    private readonly Func<bool> canExecute;

    public RelayCommand(Action execute, Func<bool> canExecute = null)
    {
        this.execute = execute;
        this.canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return canExecute == null || canExecute();      
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter) { execute(); }
}

保存"按钮:

<Button Content="Save" Command="{Binding InsertCommand}"/>

InsertCommand:

InsertCommand:

public RelayCommand InsertCommand { get; internal set; }

在ViewModel构造函数中:

In the ViewModel constructor:

InsertCommand = new RelayCommand(ExecuteInsert, CanExecuteInsert);

可以执行:

bool CanExecuteInsert()
{
    return !string.IsNullOrEmpty(Error);
}

推荐答案

您尚未真正添加足够的代码来让我们准确地告诉您您的问题是什么.但是,您正在采用正确的方法.我也使用IDataErrorInfo接口,但是我在实现它的基类中添加了一些额外的属性:

You haven't really added enough code for us to accurately tell you what your problem is. However, you are taking the correct approach. I also use the IDataErrorInfo interface, but I added some extra properties into my base class that implements it:

public string Error // actual IDataErrorInfo Member
{
    get
    {
        if (!HasError) return string.Empty;
        StringBuilder errors = new StringBuilder();
        foreach (string error in Errors) errors.AppendUniqueOnNewLineIfNotEmpty(error);
        return errors.ToString();
    }
}

public virtual ObservableCollection<string> Errors
{
    get { return errors; }
}

public virtual bool HasError
{
    get { return Errors != null && Errors.Count > 0; }
}

Errors集合仅使我能够同时维护多个错误,而HasError仅告诉我是否存在任何错误.在每种数据类型中,使用IDataErrorInfo索引器填充Errors集合:

The Errors collection just enables me to maintain multiple errors simultaneously and HasError just tells me if there are any errors or not. The Errors collection is filled using the IDataErrorInfo indexer in each data type:

public override ObservableCollection<string> Errors
{
    get
    {
        errors = new ObservableCollection<string>();
        errors.AddUniqueIfNotEmpty(this["Title"]);
        errors.AddUniqueIfNotEmpty(this["Artist"]);
        ...
        errors.AddUniqueIfNotEmpty(this["DealerPrice"]);
        return errors;
    }
}

因此,为了回答您的实际问题,我将像这样处理Save CommandCanExecute功能:

So to answer your actual question, I would handle the CanExecute functionality of the Save Command like this:

    public override ICommand Save
    {
        get { return new ActionCommand(action => SaveCommand(), canExecute => 
            CanSave(DigitalServiceProviderPriceTier)); }
    }
...
    private bool CanSave(DigitalServiceProviderPriceTier digitalServiceProviderPriceTier)
    {
        return digitalServiceProviderPriceTier != null && 
            digitalServiceProviderPriceTier.HasChanges && 
            !digitalServiceProviderPriceTier.HasError; // <-- Important part
    }

因此,似乎您几乎是在 中以相同的方式执行此操作-我的其他属性当然是可选的.如果您的Error属性从不为空,那么我会说是您的问题.首先调试它,看看它实际有什么价值……也许总有一个不应该出现的错误?

So, it seems as though you are doing this in almost the same way - my additional properties are of course optional. If your Error property is never empty, then I would say that that is your problem. Start by debugging it and seeing what value it actually has... perhaps there is always an error there that shouldn't be?

嗯...我刚刚注意到您的Error属性代码... 是您的问题:

Ahhhh... I just noticed your Error property code... that is your problem:

public string Error { get { return this[null]; } } 

您正在使用值为null的索引器调用索引,因此索引器中返回的代码实际上就是您的Error属性值.如果没有验证错误,索引器还应该返回一个空字符串:

You are calling the indexer with a value of null, so what the code in your indexer is returning is actually what your Error property value will be. An indexer should also return an empty string if there are no validation errors:

public override string this[string propertyName]
{
    get
    {
        string error = string.Empty;
        if (propertyName == "SomePropertyName" && SomePropertyName.IsNullOrEmpty()) 
            error = "You must enter some property.";
        if (propertyName == "OtherPropertyName" && OtherPropertyName.Length != 3) 
            error = "The OtherPropertyName must be 3 characters long.";
        ...
        return error;
    }
}

然后在您的Error属性中,应调用要验证的 actual 属性名称,就像我在Errors属性中所做的一样,而不是 not .因此,在上面的示例中,您可以在Error属性中调用这样的内容:

Then in your Error property, you should call the actual property names that you want to validate as I did in my Errors property and not null. So in the example above, you could call something like this in your Error property:

string error = this["SomePropertyName"];
if (error == string.Empty) error = this["OtherPropertyName"];
return error;

再一次,我写了太多信息……我只是希望这对您有意义,并且您不会再提出许多新问题.希望它已经足够清楚了.

Once again, I've written too much information... I just hope it all makes sense to you and you're not going to return with dozens of new questions. Hopefully, it's clear enough.

这篇关于具有输入验证的WPF命令绑定-如何启用“保存"功能.仅当所有输入均有效时才按的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆