65

我有一个 WPF 对话框,上面有几个文本框。文本框绑定到我的业务对象并附加了 WPF 验证规则。

问题是用户可以完美地单击“确定”按钮并关闭对话框,而无需实际将数据输入到文本框中。验证规则永远不会触发,因为用户甚至没有尝试将信息输入到文本框中。

是否可以强制验证检查并确定某些验证规则是否被破坏?

当用户尝试关闭对话框并在任何验证规则被破坏时禁止他这样做时,我将能够做到这一点。

谢谢你。

4

6 回答 6

75

在 3.5SP1 / 3.0SP2 中,他们还在 ValidationRule 基础中添加了一个新属性,即ValidatesOnTargetUpdated="True"。这将在绑定源对象后立即调用验证,而不是仅在更新目标控件时调用。这可能不是您想要的,但最初看到您需要修复的所有内容也不错。

像这样工作:

<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>
于 2009-03-21T06:49:07.223 回答
68

我们的应用程序中也存在这个问题。验证仅在绑定更新时触发,因此您必须手动更新它们。我们在 Window 的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();
}

这将使错误模板(红色轮廓)出现,并设置Validation.HasError属性,我们已触发 OK 按钮禁用该属性:

<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>
于 2009-01-30T19:28:21.643 回答
2

这是一种不需要调用“UpdateSource()”或“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);
}
于 2016-06-24T23:00:53.160 回答
0

使用 Robert Macnee 提出的上述方法。例如:

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

但是,请确保在此代码运行之前绑定的控件是可见的!

于 2012-07-25T11:57:12.167 回答
0

以防万一有人碰巧发现这个老问题并正在寻找解决 Monstieur 关于 UI 指南的评论的答案,我做了以下事情:

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>

必填字段验证规则:

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);
    }
}

在 Xaml 绑定到的类中

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
}

然后,如果我的任何对象具有 HasValidationError = true,我将使用绑定属性隐藏我的保存按钮。

希望这对某人有帮助。

于 2018-05-24T16:32:12.097 回答
-3

在您的数据对象上使用 INotifyPropertychanged

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

}

您可以将以下代码添加到您的控件

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

文本框订阅 datacontext 对象(在我们的示例中为 MyObjet)的 propertychanged 事件,并假定在更新源数据时触发它

它会自动强制刷新控件

无需调用自己的 UpdateTarget 方法

于 2010-10-11T21:26:28.337 回答