2012-04-03 5 views
15

私は多くのコントロールを持つMVVMベースのウィンドウを持っており、私のモデルはIDataErrorInfoを実装しています。IDataErrorInfoを使用してViewModelからViewで検証エラーを強制的に更新するには?

また、プロパティを分析して検証を実行するSaveCommandボタンがあります。

ビューには、特定のコントロールの値を変更した場合、またはPropertyChangedを使用してそのプロパティの変更について通知する場合にのみ、エラーのコントロールの周囲のデフォルトの赤い境界線が表示されます。

コントロールに触れていなくても、すべての検証エラーを表示するにはどうすればよいですか?

すべての検証バインディングにはValidatesOnDataErrors=True, NotifyOnValidationError=Trueが含まれています。

すべてのエラーを含む集約ボックスを用意することをお勧めしますが、コントロール単位でエラーを表示することをお勧めします。

ViewModelのバインドされたプロパティごとにModel.NotifyPropertyChangedをトリガーしたくありません。

私はSilverlightではなくWPF 4.0を使用していますので、INotifyDataErrorInfoは動作しません。

答えて

12

バインドするプロパティに対してプロパティを変更したくないということに言及していますが、これは実際にはこれを実現する最も簡単な方法です。パラメータなしでPropertyChangedを呼び出すと、viewmodelのすべてのプロパティが呼び出されます。

また、あなたがこのような任意のコントロールにバインド(力の再検証)を更新することができます

myControl.GetBindingExpression(ControlType.ControlProperty).UpdateSource(); 
+2

PropertyChangedのおかげで、ありがとう。私はそれが可能であることを知らなかった。私はこのトピックに関する別の議論を見つけました:http://stackoverflow.com/questions/1135012/wpf-mvvm-can-a-single-propertychanged-update-all-the-data-bindings-of-a-datate if誰でも興味があります。誰かが単一のシンプルなviewModelを持っている場合、これは良い答えです。しかし、私は複雑なビューを入れ子にしたViewModelを持っているので、INotifyPropertyChangedを実装している各ネストされたModel/ViewModelのPropertyChangedを一度呼び出すコードを書く必要があります – surfen

+0

ビューの一部だけを更新したい場合は、特定のViewModelに移動します。 – surfen

+0

myControl.GetBindingExpression(ControlType.ControlProperty).UpdateTarget();ソースプロパティを更新することなく、実際にあなたの検証を最新にします。 – r41n

2

私が今までに見つけた最良の解決策は、DataContextをnullに変更してViewModelのインスタンスに戻すことです。

これはInnerViewModelにバインドDataContextを持つビュー上のコントロールのための更新をトリガー:

public void ForceUpdateErrors() { 
    var tmpInnerVM = _mainViewModel.InnerViewModel; 
    _mainViewModel.InnerViewModel = null; 
    _mainViewModel.InnerViewModel = tmpInnerVM; 
} 

何もデータがこのトリック後に失われていないかどうかを確認することをお勧めします。私は、このコードがnullでComboBox.SelectedItemのソース更新を引き起こしたが、それを解決することができたというケースがあった。これは、リソースベースのBindingProxyを使用し、制御階層全体に伝播する順序がDataContext=nullであるために発生しました。

1

この「ハック」はInotifyChangedイベントを強制的に、一時的に私のために働いた、ちょうどそれが自分の背中、そのコントロールを割り当てますコンテンツ。バインディングのHasError関数を評価する前にこれを行います。たとえば、テキストボックスには、次のようになります。

((TextBox)child).Text = ((TextBox)child).Text; 

そして完全な例(私はこれが本当MVVMではありません聞く前に、私が直接このコードsnipetを示すを容易にするためにグリッド上のハンドルを持って)

 public bool Validate() 
    {   
     bool hasErr = false; 

     for (int i = 0; i != VisualTreeHelper.GetChildrenCount(grd); ++i) 
     { 
      DependencyObject child = VisualTreeHelper.GetChild(grd, i); 
      if (child is TextBox) 
      { 
       bool pp = BindingOperations.IsDataBound(child, TextBox.TextProperty); 
       if (pp) 
       { 

        ((TextBox)child).Text = ((TextBox)child).Text; 

        hasErr = BindingOperations.GetBindingExpression(child, TextBox.TextProperty).HasError; 
        System.Collections.ObjectModel.ReadOnlyCollection<ValidationError> errors = BindingOperations.GetBindingExpression(child, TextBox.TextProperty).ValidationErrors; 
        if (hasErr) 
        { 
         main.BottomText.Foreground = Brushes.Red; 
         main.BottomText.Text = BindingOperations.GetBinding(child, TextBox.TextProperty).Path.Path.Replace('.', ' ') + ": " + errors[0].ErrorContent.ToString(); 
         return false; 
        } 
       } 
      } 
      if (child is DatePicker) 
      { 
       ...      
      } 
     } 

     return true; 
    } 
関連する問題