2011-02-03 10 views
1

私は単純なwpfアプリケーションを持っており、フォームにエラーがある場合は保存ボタンを無効にしようとしています。wpf mvvmエラーの確認

問題は、それが完璧に動作するように見えますが、理由はわかりませんが、エラーをチェックする方法からすべての時間が間違っています。

私はコードを提供することでより明確にしてください。

これはこれは、ボタンのコマンド

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

Iドンである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(); 

    } 

からのコードですそれがmaかどうか知りませんどのような感覚もありますが、非アクティブ化したいボタンはUserControlにあります。

私はなぜuserControlにあるcanExecuteメソッドが複数回トリガされたのか理解できません。私が使った場合、これまでどんな方法があっても、それは同じ反応をします。 mainWindowの同じメソッド(ICommandの一部)をmainWindowで使用すると、一度だけトリガーされるので、私はuserControlについて言及します。

私は誰にも助けてくれますか?

ありがとうございました

+0

おそらくそのための2レベル参照Value.IsValid機能しません。 "RaisePropertyChanged(" SaveItem ")"のような手動でコマンドを更新してみてください。 – vorrtex

+0

@vorrtex何か提案できますか? – StrouMfios

答えて

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はViewModelにに存在している必要があります

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."); 
    } 
} 
+0

それは素晴らしい解決策ですが、私はEFを使用しているので、データアノテーションで検証を使用したいと思います。私はオリジナルの投稿を編集しました – StrouMfios

+0

@StrouMfiosデータ注釈はWPFでビルドインサポートを持たないようです。このリンクをチェックすると、http://blog.paulbetts.org/indexを実行する必要があります。php/2010/04/27/wpf-data-validation-using dataannotations/ – vorrtex

+0

@vortexリンクをありがとう、私はそれをチェックアウトします。 – StrouMfios