studio - Validación de fuerza en controles enlazados en WPF
visual studio wpf (6)
Tengo un cuadro de diálogo WPF con un par de cuadros de texto. Los cuadros de texto están vinculados a mi objeto comercial y tienen adjuntas reglas de validación de WPF.
El problema es que el usuario puede hacer clic perfectamente en el botón "Aceptar" y cerrar el 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?
Sería capaz de hacerlo cuando el usuario intente cerrar el diálogo y le prohíba hacerlo si se rompen las reglas de validación.
Gracias.
Aquí hay una forma alternativa que no requiere llamar a "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);
}
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.
Funciona de la siguiente manera:
<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>
En caso de que alguien encuentre esta vieja pregunta y busque una respuesta que aborde el comentario de Monstieur sobre las pautas de UI, hice lo siguiente:
Xaml
<TextBox.Text>
<Binding Path="TextValue" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:RequiredFieldValidationRule>
<local:RequiredFieldValidationRule.IsRequiredField>
<local:BoolValue Value="{Binding Data.Required, Source={StaticResource proxy}}" />
</local:RequiredFieldValidationRule.IsRequiredField>
<local:RequiredFieldValidationRule.ValidationFailed>
<local:BoolValue Value="{Binding Data.HasValidationError, Mode=TwoWay, Source={StaticResource proxy}}" />
</local:RequiredFieldValidationRule.ValidationFailed>
</local:RequiredFieldValidationRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
RequiredFieldValidationRule:
public class RequiredFieldValidationRule : ValidationRule
{
private BoolValue _isRequiredField;
public BoolValue IsRequiredField
{
get { return _isRequiredField; }
set { _isRequiredField = value; }
}
private BoolValue _validationFailed;
public BoolValue ValidationFailed
{
get { return _validationFailed; }
set { _validationFailed = value; }
}
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
ValidationFailed.Value = IsRequiredField.Value && (value == null || value.ToString().Length == 0);
return new ValidationResult(!ValidationFailed.Value, ValidationFailed.Value ? "This field is mandatory" : null);
}
}
En la clase a la que Xaml se une
private bool _hasValidationError;
public bool HasValidationError
{
get { return _hasValidationError; }
set { _hasValidationError = value; NotifyPropertyChanged(nameof(HasValidationError)); }
}
public void InitialisationMethod() // Or could be done in a constructor
{
_hasValidationError = Required; // Required is a property indicating whether the field is mandatory or not
}
Luego oculto mi botón Guardar usando una propiedad vinculada, si alguno de mis objetos tiene HasValidationError = true.
Espero que esto sea útil para alguien.
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 Window''s 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 aparezca la plantilla de error (contorno rojo) y establezca la propiedad Validation.HasError , que activamos 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>
Use 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();
}
}
¡ASEGÚRESE de que los controles vinculados sean Visibles antes de ejecutar este código!
utilizando INotifyPropertychanged en su objeto de 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
}
puedes agregar el siguiente código a tu control
<TextBox Text="{Binding MyPropertyToBind, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
El cuadro de texto se suscribe al evento de cambio de propiedad del objeto de contexto de datos (MyObjet en nuestro ejemplo) y asume que se dispara cuando los datos de origen se han actualizado
fuerza automáticamente la actualización al control
No es necesario que te llames el método UpdateTarget