2009-01-27 7 views
51

Tengo un cuadro de diálogo WPF con un par de cuadros de texto en él. Los cuadros de texto están vinculados a mi objeto comercial y tienen adjuntas reglas de validación de WPF.Validación de fuerza en controles vinculados en WPF

El problema es que el usuario puede hacer clic perfectamente en el botón "Aceptar" y cerrar el cuadro de diálogo, sin ingresar los datos en cuadros de texto. Las reglas de validación nunca se activan, ya que el usuario ni siquiera intentó ingresar la información en cuadros de texto.

¿Es posible forzar comprobaciones de validación y determinar si algunas reglas de validación están rotas?

Podría hacerlo cuando el usuario intente cerrar el diálogo y prohibirle hacerlo si se rompen las reglas de validación.

Gracias.

Respuesta

56

Tenemos este problema en nuestra aplicación también. La validación solo se activa cuando se actualizan los enlaces, por lo que debe actualizarlos manualmente. Hacemos esto en el evento de la ventana Loaded:

public void Window_Loaded(object sender, RoutedEventArgs e) 
{ 
    // we manually fire the bindings so we get the validation initially 
    txtName.GetBindingExpression(TextBox.TextProperty).UpdateSource(); 
    txtCode.GetBindingExpression(TextBox.TextProperty).UpdateSource(); 
} 

Esto hará que la plantilla de error (línea roja) aparecerá, y establezca la propiedad Validation.HasError, que hemos desencadenar el botón OK para desactivar:

<Button x:Name="btnOK" Content="OK" IsDefault="True" Click="btnOK_Click"> 
    <Button.Style> 
     <Style TargetType="{x:Type Button}"> 
      <Setter Property="IsEnabled" Value="false" /> 
      <Style.Triggers> 
       <!-- Require the controls to be valid in order to press OK --> 
       <MultiDataTrigger> 
        <MultiDataTrigger.Conditions> 
         <Condition Binding="{Binding ElementName=txtName, Path=(Validation.HasError)}" Value="false" /> 
         <Condition Binding="{Binding ElementName=txtCode, Path=(Validation.HasError)}" Value="false" /> 
        </MultiDataTrigger.Conditions> 
        <Setter Property="IsEnabled" Value="true" /> 
       </MultiDataTrigger> 
      </Style.Triggers> 
     </Style> 
    </Button.Style> 
</Button> 
+9

Esto funciona y logra lo que estaba buscando, pero no tengo código subyacente. La lógica de formulario está encapsulada en un ModelView.Como se supone que ModelView no tiene referencias a elementos de pantalla específicos, ¿cómo se puede hacer esto y aún no tener código subyacente? ¿Hay alguna forma en XAML para forzar el enlace? – Kilhoffer

+0

¿Qué sucede si no tiene un elemento con nombre? ¿y si es parte de una plantilla en ItemsControl? –

+0

Hola soy un recién llegado, pero estoy seguro de que esto es lo que quiero como funcionalidades. Ahora mi problema es que mi aplicación se está conectando a un servicio web para cualquiera de sus funcionalidades. Eso significa que no tengo el modelo de datos en mi aplicación . Honestamente estoy buscando una forma de hacer la validación sin enlace de datos. ¿Puede alguien mostrarme el camino a seguir? gracias –

60

En 3.5SP1/3.0SP2, también agregaron una nueva propiedad a la base ValidationRule, a saber, ValidatesOnTargetUpdated="True". Esto llamará a la validación tan pronto como se vincule el objeto fuente, en lugar de solo cuando se actualice el control objetivo. Puede que eso no sea exactamente lo que quieres, pero no está mal ver inicialmente todo lo que necesitas arreglar.

Obras algo como esto:

<TextBox.Text> 
    <Binding Path="Amount" StringFormat="C"> 
     <Binding.ValidationRules> 
      <validation:RequiredValidationRule 
       ErrorMessage="The pledge amount is required." 
       ValidatesOnTargetUpdated="True" /> 
      <validation:IsNumericValidationRule 
       ErrorMessage="The pledge amount must be numeric." 
       ValidationStep="ConvertedProposedValue" 
       ValidatesOnTargetUpdated="True" /> 
     </Binding.ValidationRules> 
    </Binding> 
</TextBox.Text> 
+0

+1 para salvar mi vida ;-) – Nils

+1

Esta propiedad es realmente genial, simple y hace exactamente lo que necesitamos. –

+0

Me alegra que hayan agregado esto. –

-3

utilizando el INotifyPropertyChanged en el objeto de sus datos

public class MyObject : INotifyPropertyChanged 
{ 
    string _MyPropertyToBind = string.Empty; 
    public string MyPropertyToBind 
    { 
     get 
     { 
      return _MyPropertyToBind; 
     } 
     set 
     { 
      _MyPropertyToBind = value; 
      NotifyPropertyChanged("MyPropertyToBind"); 
     } 
    } 

    public void NotifyPropertyChanged(string property) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged(this, new PropertyChangedEventArgs(property)); 
     } 
    } 
    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 

    #endregion 

} 

se puede añadir el siguiente código a su control de

<TextBox Text="{Binding MyPropertyToBind, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" > 

El cuadro de texto susbscribe a el evento de cambio de propiedad del objeto de contexto de datos (MyObjet en nuestro ejemplo) a nd asume que se activa cuando el origen de datos se ha actualizado

obliga automáticamente la actualización al control

No hay necesidad de decir que eres el método UpdateTarget

+0

No prestó atención a la pregunta. Ninguna propiedad está siendo cambiada. –

0

Utilice el método anterior propuesto por Robert Macnee. Por ejemplo:

//force initial validation 
foreach (FrameworkElement item in grid1.Children) 
{ 
    if (item is TextBox) 
    { 
     TextBox txt = item as TextBox; 
     txt.GetBindingExpression(TextBox.TextProperty).UpdateSource(); 
    } 
}   

Pero, asegúrese de que los controles dependientes son Visibles antes de este código de ejecución!

+0

Es curioso, cómo recibo los comentarios sobre una pregunta que hice hace 3.5 años, y desde entonces no estoy programando en Windows. Pero gracias de todos modos – Valentin

+1

@ValentinVasilyev Probablemente porque los televidentes con una respuesta quieren ayudar a más personas (aparte de la que hace la pregunta). Probablemente ya lo sepas, la razón por la que aún respondí (nuevamente, después de algunos años) es la misma razón que mencioné). – MasterMastic

1

Aquí es una forma alternativa que no requiere llamar "UpdateSource()" o "UpdateTarget()":

var binding = thingToValidate.GetBinding(propertyToValidate); 
foreach (var rule in binding.ValidationRules) 
{ 
    var value = thingToValidate.GetValue(propertyToValidate); 
    var result = rule.Validate(value, CultureInfo.CurrentCulture); 
    if (result.IsValid) 
     continue; 
    var expr = BindingOperations.GetBindingExpression(thingToValidate, propertyToValidate); 
    if (expr == null) 
     continue; 
    var validationError = new ValidationError(rule, expr); 
    validationError.ErrorContent = result.ErrorContent; 
    Validation.MarkInvalid(expr, validationError); 
} 
Cuestiones relacionadas