Подтвердить что ты не робот

Проверка синтаксиса связанных элементов управления в WPF

У меня есть диалог WPF с несколькими текстовыми полями на нем. Текстовые поля привязаны к моему бизнес-объекту и имеют правила проверки WPF.

Проблема в том, что пользователь может отлично нажать кнопку "ОК" и закрыть диалоговое окно, фактически не введя данные в текстовые поля. Правила проверки никогда не срабатывают, поскольку пользователь даже не пытался ввести информацию в текстовые поля.

Можно ли принудительно выполнить проверки проверки и определить, нарушены ли некоторые правила проверки?

Я мог бы сделать это, когда пользователь попытается закрыть диалог и запретить ему делать это, если будут нарушены какие-либо правила проверки.

Спасибо.

4b9b3361

Ответ 1

У нас есть эта проблема и в нашем приложении. Проверка выполняется только при обновлении привязок, поэтому вам необходимо обновить их вручную. Мы делаем это в окне 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>

Ответ 2

В 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>

Ответ 3

Вот альтернативный способ, который не требует вызова "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);
}

Ответ 4

Используйте метод, предложенный Робертом Макни. Например:

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

Но, УБЕДИТЕСЬ, что связанные элементы управления являются Visibles до запуска этого кода!

Ответ 5

используя 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}" >

Текстовое поле воспринимает событие propertychanged объекта datacontext (MyObjet в нашем примере) и предполагает, что оно запущено, когда исходные данные были обновлены.

он автоматически принудительно обновляет элемент управления

Не нужно называть себя методом UpdateTarget