2014-04-16 29 views
0

在我的ViewModel中,我實現了IDataErrorInfo接口(以及INotifyPropertyChanged)。輸入驗證按預期工作,我在那裏沒有問題。WPF命令與輸入驗證綁定 - 如何僅在所有輸入有效時啓用「保存」按鈕

我有這樣的屬性作爲IDataErrorInfo的public string Error { get { return this[null]; } }的一部分,據我瞭解,Error應該是空的,如果所有的驗證輸入通過驗證,所以我通過這個作爲我的CanExecute方法

return !string.IsNullOrEmpty(Error); 

但是,我的「保存」按鈕從未啓用。我的感覺是,CanExecuteChanged從來沒有得到激怒。如果那是真的,我應該在哪裏以及如何觸發它?


這是我的RelayCommand類。我嘗試了其他的實施方式,但結果是一樣的。我認爲它可以工作,因爲如果我沒有將CanExecute方法傳遞給構造函數,「save」按鈕將被啓用。

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:

public RelayCommand InsertCommand { get; internal set; } 

在視圖模型構造:

InsertCommand = new RelayCommand(ExecuteInsert, CanExecuteInsert); 

CanExecute:

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

顯示InsertCommand它是如何初始化的以及它的CanExecute –

+0

@lll在最後添加它。 –

回答

4

您還沒有真正地爲我們添加足夠的代碼來準確地告訴您您的問題是什麼。但是,您正在採取正確的方法。我還使用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; } 
} 

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; 
    } 
} 

所以回答您的實際問題,我會處理Save Command這樣的CanExecute功能:

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屬性永遠不是空的,那麼我會說是你的問題。開始調試它,看看它實際上有什麼價值......也許總會有一個錯誤,那不應該是?

Ahhhh ...我只注意到你的Error屬性代碼...是你的問題:

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

要調用與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; 
    } 
} 

然後在你的Error財產,你應該叫您要驗證我在Errors財產做了實際屬性名稱和不是null。所以在上面的例子中,你可以把這樣的事情在你的Error屬性:再次

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

,我已經寫了太多的信息.​​.....我只希望這一切有意義的你和你不會有幾十個新問題返回。希望這很清楚。

+0

我剛剛開始使用WPF,並且在IDataErrorInfo的所有示例中,Error屬性都是這樣實現的。它適用於驗證,所以我不認爲這是一個問題。 我會回家時嘗試你的建議。 –

+0

它的工作,謝謝!我在這裏也有一個邏輯缺陷 'return!string.IsNullOrEmpty(Error);' 當然,它應該沒有否定。 –