2011-02-03 110 views
1

我有一个简单的WPF应用程序,如果窗体有错误,我试图关闭保存按钮。wpf mvvm错误验证

问题是,虽然它的验​​证看起来很完美,但我不知道为什么,但我总是从负责检查错误的方法中得到错误。

让我通过提供代码更清楚。

这是从MainWindow.Xaml.cs

private readonly HashSet<ValidationError> errors = new HashSet<ValidationError>(); 
    private Lazy<MainWindowViewModel> viewModel; 

    public MainWindow() { 
     InitializeComponent(); 
     InitializeValidaton(); 
    } 

    void InitializeValidaton() { 
     viewModel = new Lazy<MainWindowViewModel>(); 
     Validation.AddErrorHandler(this, ErrorChangedHandler); 
    } 

    private void ErrorChangedHandler(object sender, ValidationErrorEventArgs e) { 
     if (e.Action == ValidationErrorEventAction.Added) { 
      errors.Add(e.Error); 
     } else { 
      errors.Remove(e.Error); 
     } 
     //I set a breakpoint here and it returns the correct value. False if it has errors and True if not 
     viewModel.Value.IsValid = !errors.Any(); 

    } 

代码这是为按钮

public ICommand SaveItem { 
     get { return new RelayCommand(SaveItemExecute,CanSaveItem); } 
    } 
private bool CanSaveItem() { 
     return IsValid; 
    } 

    //I set up here a breakpoint and it returns the correct value just once. 
    //The application looked up on CanSaveItem all the time and except the first time, it returns wrong value 
    private bool _isValid; 
    public bool IsValid { 
     get { return _isValid; } 
     set { 
      _isValid = value; 
      RaisePropertyChanged("IsValid"); 
    } 
    } 

验证规则

[Required(ErrorMessage = "Please enter Title")] 
    [StringLength(100, ErrorMessage = "The maximum length is 100")] 
    string Name { get; set; } 

我不命令不知道它是否可以kes任何意义,但我想停用的按钮在UserControl中。

我不明白为什么canExecute方法在userControl中触发多次。如果我使用了什么方法,它有相同的反应。我提到了userControl,因为如果我在mainWindow中使用相同的方法(在ICommand中),它只触发一次

如果有人能帮助我,我将不胜感激。

谢谢

+0

也许它不会因为2级参考Value.IsValid工作。尝试手动更新命令,类似于“RaisePropertyChanged(”SaveItem“)”。 – vorrtex 2011-02-03 15:02:16

+0

@vorrtex你能提出什么建议吗? – StrouMfios 2011-02-03 16:58:46

回答

4

我宁愿发表一个验证使用您的模型的工作示例。根据需要调整此示例,并且可能会发现产生不正确工作的差异。

MainWindow.xaml

<StackPanel> 
    <TextBox x:Name="ValidatedTextBox" Width="200"> 
     <TextBox.Text> 
      <Binding Path="EnteredText" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True"> 
       <Binding.ValidationRules> 
        <local:NotEmptyInputRule ValidatesOnTargetUpdated="True" /> 
       </Binding.ValidationRules> 
      </Binding> 
     </TextBox.Text> 
    </TextBox> 
    <Button Content="Save" Width="60" IsEnabled="{Binding IsValid}" /> 
</StackPanel> 

物业EnteredText必须存在于视图模型:

class MainWindowViewModel : INotifyPropertyChanged 
{ 
    public ICommand SaveItem 
    { 
     get { return new SimpleCommand(SaveItemExecute, CanSaveItem); } 
    } 

    public void SaveItemExecute() 
    { 
     //save 
    } 

    private bool CanSaveItem() 
    { 
     return IsValid; 
    } 

    //I set up here a breakpoint and it returns the correct value just once. 
    //The application looked up on CanSaveItem all the time and except the first time, it returns wrong value 
    private bool _isValid; 
    public bool IsValid 
    { 
     get { return _isValid; } 
     set 
     { 
      _isValid = value; 
      OnPropertyChanged("IsValid"); 
     } 
    } 

    public string EnteredText { get; set; } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

} 

而且不要忘记设置DataContext在主窗口。

public MainWindow() 
    { 
     InitializeComponent(); 
     InitializeValidaton(); 
     this.DataContext = viewModel.Value; 
    } 

还有Command类和验证规则。

public class SimpleCommand : ICommand 
{ 
    /// <summary> 
    /// Gets or sets the Predicate to execute when the CanExecute of the command gets called 
    /// </summary> 
    public Predicate<object> CanExecuteDelegate { get; set; } 

    /// <summary> 
    /// Gets or sets the action to be called when the Execute method of the command gets called 
    /// </summary> 
    public Action<object> ExecuteDelegate { get; set; } 

    public SimpleCommand(Action execute, Func<bool> canExecute) 
    { 
     this.ExecuteDelegate = _ => execute(); 
     this.CanExecuteDelegate = _ => canExecute(); 
    } 

    #region ICommand Members 

    /// <summary> 
    /// Checks if the command Execute method can run 
    /// </summary> 
    /// <param name="parameter">THe command parameter to be passed</param> 
    /// <returns>Returns true if the command can execute. By default true is returned so that if the user of SimpleCommand does not specify a CanExecuteCommand delegate the command still executes.</returns> 
    public bool CanExecute(object parameter) 
    { 
     if (CanExecuteDelegate != null) 
      return CanExecuteDelegate(parameter); 
     return true;// if there is no can execute default to true 
    } 

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

    /// <summary> 
    /// Executes the actual command 
    /// </summary> 
    /// <param name="parameter">THe command parameter to be passed</param> 
    public void Execute(object parameter) 
    { 
     if (ExecuteDelegate != null) 
      ExecuteDelegate(parameter); 
    } 

    #endregion 

}

class NotEmptyInputRule : ValidationRule 
{ 
    public override ValidationResult Validate(object value, CultureInfo cultureInfo) 
    { 
     if (value != null) 
     { 
      string input = value as string; 

      if (input.Length > 0) 
       return new ValidationResult(true, null); 
     } 

     return new ValidationResult(false, "Validation error. Field input required."); 
    } 
}