2014-04-16 8 views
0

내 ViewModel에서 IDataErrorInfo 인터페이스를 구현했습니다 (INotifyPropertyChanged와 함께). 입력 유효성 검사가 의도 한대로 작동하지만 문제가 없습니다.입력 유효성 검사를 사용하는 WPF 명령 바인딩 - 모든 입력이 유효한 경우에만 "저장"단추를 활성화하는 방법

나는 모든 검증 입력이 유효성 검사를 통과하면 Error가 비어 있어야합니다, 나의 이해에 IDataErrorInfo public string Error { get { return this[null]; } }의 일환으로이 속성을 가지고, 그래서 난 내 CanExecute 방법

return !string.IsNullOrEmpty(Error); 

하지만, 내 "저장"버튼으로이 통과 활성화되지 않습니다. 제 말은 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(); } 
} 

"저장"버튼 :

<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

삽입 명령 표시 초기화 된 방법 및 해당 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 그냥 나에게 말한다 아니. 그래서

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 
    } 

을 :

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 기능을 처리 할 다음 Errors 수집은 각 데이터 유형에 IDataErrorInfo 인덱서를 사용하여 가득 에서 거의 동일한 방식으로에서이 작업을 수행하는 것처럼 보입니다. 추가 속성은 물론 선택 사항입니다. Error 속성이 비어 있지 않은 경우 인 것이 좋습니다. 디버깅을 시작하고 실제로 어떤 가치를 지니고 있는지 살펴 보는 것부터 시작해야합니다.

아 ... 나는 방금 Error 속성 코드를 발견했습니다.당신은 null의 가치, 그래서 당신의 인덱서의 코드가 반환하여 Error 속성 값이 될 것입니다 무엇을 실제로와 인덱서를 호출

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

: 가 문제입니다.

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); ' 물론 부정을하지 말아야한다. –