Saš*_*vić 1 wpf mvvm idataerrorinfo relaycommand icommand
在我的ViewModel中,我实现了IDataErrorInfo接口(以及INotifyPropertyChanged)。输入验证按预期工作,我在那里没有问题。
我将此属性作为IDataErrorInfo的一部分,public string Error { get { return this[null]; } }据我了解,Error如果所有已验证的输入均通过验证,则应为空,因此我将此作为我的CanExecute方法传递
return !string.IsNullOrEmpty(Error);
Run Code Online (Sandbox Code Playgroud)
但是,我的“保存”按钮从未启用。我的CanExecuteChanged猜想是永远不会被触发。如果是这样,我应该在哪里以及如何触发它?
这是我的RelayCommand类。我尝试了其他实现方式,但结果相同。我认为它有效,因为如果不将CanExecute方法传递给构造函数,则会启用“保存”按钮。
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(); }
}
Run Code Online (Sandbox Code Playgroud)
“保存”按钮:
<Button Content="Save" Command="{Binding InsertCommand}"/>
Run Code Online (Sandbox Code Playgroud)
InsertCommand:
public RelayCommand InsertCommand { get; internal set; }
Run Code Online (Sandbox Code Playgroud)
在ViewModel构造函数中:
InsertCommand = new RelayCommand(ExecuteInsert, CanExecuteInsert);
Run Code Online (Sandbox Code Playgroud)
可以执行:
bool CanExecuteInsert()
{
return !string.IsNullOrEmpty(Error);
}
Run Code Online (Sandbox Code Playgroud)
您尚未真正为我们添加足够的代码来准确地告诉您您的问题是什么。但是,您正在采用正确的方法。我也使用该IDataErrorInfo接口,但是我在实现它的基类中添加了一些额外的属性:
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; }
}
Run Code Online (Sandbox Code Playgroud)
该Errors集合使我能够同时维护多个错误,并HasError告诉我是否存在任何错误。该Errors集合使用填充IDataErrorInfo在每个数据类型索引:
public override ObservableCollection<string> Errors
{
get
{
errors = new ObservableCollection<string>();
errors.AddUniqueIfNotEmpty(this["Title"]);
errors.AddUniqueIfNotEmpty(this["Artist"]);
...
errors.AddUniqueIfNotEmpty(this["DealerPrice"]);
return errors;
}
}
Run Code Online (Sandbox Code Playgroud)
因此,要回答您的实际问题,我将处理如下CanExecute功能Save Command:
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
}
Run Code Online (Sandbox Code Playgroud)
因此,似乎您几乎以相同的方式执行此操作-我的其他属性当然是可选的。如果您的Error财产永远都不为空,那我想那就是您的问题。首先调试它,看看它实际有什么价值……也许总有一个错误不应该存在?
啊...我刚刚注意到您的Error财产代码... 那就是您的问题:
public string Error { get { return this[null]; } }
Run Code Online (Sandbox Code Playgroud)
您正在使用值为调用索引器null,因此索引器中返回的代码实际上就是您的Error属性值。如果没有验证错误,索引器还应该返回一个空字符串:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,在您的Error媒体资源中,您应该像在我的媒体资源中那样调用要验证的实际媒体名称,Errors而不是 null。因此,在上面的示例中,您可以在Error媒体资源中调用如下代码:
string error = this["SomePropertyName"];
if (error == string.Empty) error = this["OtherPropertyName"];
return error;
Run Code Online (Sandbox Code Playgroud)
再一次,我写了太多的信息...我只是希望这对您有意义,并且您不会再提出许多新问题。希望它已经足够清楚了。
| 归档时间: |
|
| 查看次数: |
4320 次 |
| 最近记录: |