2010-06-30 3 views
7

Ho un UserControl WPF con molti altri controlli al suo interno. I TextBox sono tra questi. Ogni TextBox ha una sua validazione:Convalida WPF: azzeramento di tutti gli errori di convalida

<TextBox> 
    <TextBox.Text> 
     <Binding Path="MyPath" StringFormat="{}{0:N}" NotifyOnValidationError="True"> 
      <Binding.ValidationRules> 
       <r:MyValidationRule ValidationType="decimal" /> 
      </Binding.ValidationRules> 
     </Binding> 
    <TextBox.Text> 
<TextBox> 

un

Ora supponiamo che l'utente digita alcuni caratteri non validi in loro. Verranno tutti evidenziati in rosso.

Ora voglio ripristinare tutti gli errori di validazione (dal immissione errata) e impostare i valori corretti recenti provenienti da DataContext.

ho impostato il DataContext nel costruttore e non voglio cambiarlo (DataContext = null non mi aiuterà poi):

DataContext = _myDataContext = new MyDataContext(..); 

Quello che ho già trovato sono queste classi:

Validation.ClearInvalid(..) 
BindingExpression.UpdateTarget(); 

credo che queste classi potevano aiutarmi, ma richiedono l'Binding di una concreta FrameworkElement e voglio farlo a livello globale per tutti loro.

Devo comunque ripetere l'albero visivo (che è davvero quello che non mi piace) o c'è una soluzione migliore per questo?

+0

Quando si esegue il bind dei valori corretti, automaticamente verranno ripristinati gli errori di convalida.Stai usando l'interfaccia INotifyPropertyChanged sul tuo viewmodel e la proprietà genererà l'evento cambiato proprietà? – Ragunathan

+0

Sì, lo sto usando .. questo è quello che ho provato all'inizio. Ma non vi è alcun cambiamento nel DataSource. Quindi WPF non rifletterà il vecchio valore –

risposta

2

Questo è ciò che un BindingGroup è per ... Si potrebbe impostare un BindingGroup su un contenitore di tutte le controlli, ad es il pannello che li contiene. Ciò causerebbe la conservazione degli aggiornamenti a DataContext fino a quando non si chiama UpdateSources sul BindingGroup. Se si desidera reimpostare l'input dell'utente, si inviterà a chiamare CancelEdit e BindingGroup reimposterà tutti i controlli all'interno del contenitore ai valori (ancora invariati) di DataContext.

1

Perché non attiverai NotifyPropertyChanged per tutte le proprietà dell'origine dati? Questo aggiornerà il binding e i controlli dell'interfaccia utente dovrebbero ottenere valori da datacontext (che sono validi, quindi gli errori di validazione verranno cancellati)?

+0

No .. Ho provato questo come prima .. non ha funzionato: -/ –

+0

Oh, capito, funziona per me perché io uso l'opzione ValidatesOnExceptions e gettare eccezioni di validazione in setter. Quindi i valori originali (validi) non vengono sostituiti con non validi. – Andrii

0

io non sono sicuro di cosa si intende per

ho impostato il DataContext nel costruttore e non voglio cambiarlo (DataContext = null non mi aiuterà poi)

generale per ripristinare tutti gli attacchi sul modulo di effettuare le seguenti operazioni: (assumendo un controller per le viste/cablaggio viewmodel, altrimenti basta usare un code-behind per la vista.)

var dataContext = view.DataContext; 
view.DataContext = null; 
view.DataContext = dataContext; 

Non lo modifica in un nuovo contesto dati, ma semplicemente elimina il contesto dei dati e lo ricarica. Questo avvia tutti i binding per ricaricarli.

1

Ho avuto lo stesso problema. Più controlli convalidati su una pagina. Ho trovato/ha reso questa soluzione per aggiornare (e cancellare tutta la convalida da) i descentents di un DependencyObject:

using System.Linq; 
using System.Windows; 
using System.Windows.Data; 
using System.Windows.Media; 

/// <summary> 
/// Updates all binding targets where the data item is of the specified type. 
/// </summary> 
/// <param name="root">The root.</param> 
/// <param name="depth">The depth.</param> 
/// <param name="dataItemType">Type of the data item.</param> 
/// <param name="clearInvalid">Clear validation errors from binding.</param> 
public static void UpdateAllBindingTargets(this DependencyObject root, int depth, Type dataItemType, bool clearInvalid) 
{ 
    var bindingExpressions = EnumerateDescendentsBindingExpressions(root, depth); 
    foreach (BindingExpression be in bindingExpressions.Where(be => be.DataItem != null && be.DataItem.GetType() == dataItemType)) 
    { 
     if (be != null) 
     { 
      be.UpdateTarget(); 
      if (clearInvalid) 
       System.Windows.Controls.Validation.ClearInvalid(be); 
     } 
    } 
} 

/// <summary> 
/// Enumerates all binding expressions on descendents. 
/// </summary> 
/// <param name="root">The root.</param> 
/// <param name="depth">The depth.</param> 
/// <returns></returns> 
public static IEnumerable<BindingExpression> EnumerateDescendentsBindingExpressions(this DependencyObject root, int depth) 
{ 
    return root.EnumerateDescendents(depth).SelectMany(obj => obj.EnumerateBindingExpressions()); 
} 

/// <summary> 
/// Enumerates the descendents of the specified root to the specified depth. 
/// </summary> 
/// <param name="root">The root.</param> 
/// <param name="depth">The depth.</param> 
public static IEnumerable<DependencyObject> EnumerateDescendents(this DependencyObject root, int depth) 
{ 
    int count = VisualTreeHelper.GetChildrenCount(root); 
    for (int i = 0; i < count; i++) 
    { 
     var child = VisualTreeHelper.GetChild(root, i); 
     yield return child; 
     if (depth > 0) 
     { 
      foreach (var descendent in EnumerateDescendents(child, --depth)) 
       yield return descendent; 
     } 
    } 
} 

/// <summary> 
/// Enumerates the binding expressions of a Dependency Object. 
/// </summary> 
/// <param name="element">The parent element.</param> 
public static IEnumerable<BindingExpression> EnumerateBindingExpressions(this DependencyObject element) 
{ 
    if (element == null) 
    { 
     throw new ArgumentNullException("element"); 
    } 

    LocalValueEnumerator lve = element.GetLocalValueEnumerator(); 

    while (lve.MoveNext()) 
    { 
     LocalValueEntry entry = lve.Current; 

     if (BindingOperations.IsDataBound(element, entry.Property)) 
     { 
      if (entry.Value is PriorityBindingExpression) 
      { 
       foreach (BindingExpression expr in ((PriorityBindingExpression)entry.Value).BindingExpressions) 
        yield return expr; 
      } 
      else if (entry.Value is MultiBindingExpression) 
      { 
       foreach (BindingExpression expr in ((MultiBindingExpression)entry.Value).BindingExpressions) 
        yield return expr; 
      } 
      else 
       yield return entry.Value as BindingExpression; 
     } 
    } 
}