2010-06-30 14 views
7

Tengo un WPF UserControl con muchos otros controles dentro de él. Los cuadros de texto se encuentran entre estos. Cada cuadro de texto tiene su propia validación:Validación de WPF: Borrado de todos los errores de validación

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

un

Ahora supongamos que el usuario escribe algunos caracteres no válidos en ellos. Todos se resaltarán en rojo.

Ahora quiero restablecer todos los errores de validación (desde la entrada incorrecta) y establecidos los últimos valores correctos procedentes de DataContext.

que establezca el DataContext en el constructor y no quiero cambiarlo (DataContext = null no me ayudará a continuación):

DataContext = _myDataContext = new MyDataContext(..); 

Lo que ya he encontrado son estas clases:

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

creo que estas clases me podían ayudar, pero requieren la Binding de un hormigón FrameworkElement y quiero hacerlo a nivel mundial para todos ellos.

Debo de alguna manera iterar a través del Visual Tree (que es realmente lo que no me gusta) o hay alguna mejor solución para esto?

+0

Cuando enlaza los valores correctos, automáticamente restablecerá los errores de validación.¿Está utilizando la interfaz INotifyPropertyChanged para su viewmodel & Property levantará el evento de propiedad cambiada? – Ragunathan

+0

Sí, lo estoy usando ... eso es lo que he intentado al principio. Pero no hay cambios en el DataSource. Por lo tanto, WPF no reflejará el antiguo valor –

Respuesta

2

Esto es lo que un BindingGroup es para ... Se podría establecer un BindingGroup en un contenedor de toda la controles, por ejemplo el panel que los contiene. Esto provocaría que las actualizaciones de DataContext se retengan hasta que llame a UpdateSources en BindingGroup. Si desea restablecer la entrada del usuario, debería llamar a CancelEdit en su lugar, y BindingGroup restablecería todos los controles dentro del contenedor a los valores (aún no modificados) del DataContext.

1

¿Por qué no acaba de desencadenar NotifyPropertyChanged para todas las propiedades de su fuente de datos? Esto actualizará el enlace y los controles de UI deberían obtener valores del contexto de datos (que son válidos, por lo tanto, los errores de validación se borrarán).

+0

No ... Lo intenté primero ... no funcionó: -/ –

+0

Oh, lo tengo, funciona para mí porque uso la opción ValidatesOnExceptions y lanzo excepciones de validación en Setters. Por lo tanto, los valores originales (válidos) no se invalidan y no son válidos. – Andrii

0

no estoy seguro de lo que entendemos por

fijo el DataContext en el constructor y no quiero cambiarlo (DataContext = null no me va a ayudar a continuación)

general para restablecer todos los enlaces en la forma de hacer lo siguiente: (suponiendo un controlador de puntos de vista/cableado modelo de vista, de lo contrario sólo tiene que utilizar un código subyacente en la vista.)

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

No lo cambia a un nuevo contexto de datos, solo elimina el contexto de datos y lo vuelve a cargar. Esto inicia todas las vinculaciones para volver a cargar.

1

Tuve el mismo problema. Múltiples controles validados en una página. He encontrado/hizo esta solución para actualizar (y borrar toda la validación de) los descentents de 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; 
     } 
    } 
} 
Cuestiones relacionadas