문제

WPF에서는 다음을 사용하여 데이터 바인딩 중에 데이터 레이어에 발생한 오류를 기반으로 유효성 검사를 설정할 수 있습니다. ExceptionValidationRule 또는 DataErrorValidationRule.

이런 식으로 많은 컨트롤이 설정되어 있고 저장 버튼이 있다고 가정해 보겠습니다.사용자가 저장 버튼을 클릭하면 저장을 진행하기 전에 유효성 검사 오류가 없는지 확인해야 합니다.유효성 검사 오류가 있으면 이를 지적하고 싶을 것입니다.

WPF에서 데이터 바인딩된 컨트롤에 유효성 검사 오류가 설정되어 있는지 어떻게 알 수 있나요?

도움이 되었습니까?

해결책

이 게시물은 매우 도움이되었습니다. 기여한 모든 분들께 감사드립니다. 다음은 사랑하거나 미워할 LINQ 버전입니다.

private void CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = IsValid(sender as DependencyObject);
}

private bool IsValid(DependencyObject obj)
{
    // The dependency object is valid if it has no errors and all
    // of its children (that are dependency objects) are error-free.
    return !Validation.GetHasError(obj) &&
    LogicalTreeHelper.GetChildren(obj)
    .OfType<DependencyObject>()
    .All(IsValid);
}

다른 팁

다음 코드 (Chris Sell & Ian Griffiths의 WPF Book 프로그래밍에서)는 종속성 객체 및 그 어린이에 대한 모든 바인딩 규칙을 검증합니다.

public static class Validator
{

    public static bool IsValid(DependencyObject parent)
    {
        // Validate all the bindings on the parent
        bool valid = true;
        LocalValueEnumerator localValues = parent.GetLocalValueEnumerator();
        while (localValues.MoveNext())
        {
            LocalValueEntry entry = localValues.Current;
            if (BindingOperations.IsDataBound(parent, entry.Property))
            {
                Binding binding = BindingOperations.GetBinding(parent, entry.Property);
                foreach (ValidationRule rule in binding.ValidationRules)
                {
                    ValidationResult result = rule.Validate(parent.GetValue(entry.Property), null);
                    if (!result.IsValid)
                    {
                        BindingExpression expression = BindingOperations.GetBindingExpression(parent, entry.Property);
                        System.Windows.Controls.Validation.MarkInvalid(expression, new ValidationError(rule, expression, result.ErrorContent, null));
                        valid = false;
                    }
                }
            }
        }

        // Validate all the bindings on the children
        for (int i = 0; i != VisualTreeHelper.GetChildrenCount(parent); ++i)
        {
            DependencyObject child = VisualTreeHelper.GetChild(parent, i);
            if (!IsValid(child)) { valid = false; }
        }

        return valid;
    }

}

저장 버튼에서 전화 할 수 있습니다. 페이지/창에서 이와 같은 이벤트 핸들러를 클릭하십시오.

private void saveButton_Click(object sender, RoutedEventArgs e)
{

  if (Validator.IsValid(this)) // is valid
   {

    ....
   }
}

ListBox를 사용할 때 게시 된 코드가 작동하지 않았습니다. 나는 그것을 다시 작성하고 이제 작동합니다.

public static bool IsValid(DependencyObject parent)
{
    if (Validation.GetHasError(parent))
        return false;

    // Validate all the bindings on the children
    for (int i = 0; i != VisualTreeHelper.GetChildrenCount(parent); ++i)
    {
        DependencyObject child = VisualTreeHelper.GetChild(parent, i);
        if (!IsValid(child)) { return false; }
    }

    return true;
}

같은 문제가 있었고 제공된 솔루션을 시도했습니다. H-MAN2와 SKIBA_K의 솔루션의 조합은 한 가지 예외를 위해 거의 잘 작동했습니다. 내 창에는 TabControl이 있습니다. 그리고 유효성 검사 규칙은 현재 보이는 Tabitem에 대해서만 평가됩니다. 그래서 LogicalTreeHelper로 VisureTreeHelper를 교체했습니다. 이제 작동합니다.

    public static bool IsValid(DependencyObject parent)
    {
        // Validate all the bindings on the parent
        bool valid = true;
        LocalValueEnumerator localValues = parent.GetLocalValueEnumerator();
        while (localValues.MoveNext())
        {
            LocalValueEntry entry = localValues.Current;
            if (BindingOperations.IsDataBound(parent, entry.Property))
            {
                Binding binding = BindingOperations.GetBinding(parent, entry.Property);
                if (binding.ValidationRules.Count > 0)
                {
                    BindingExpression expression = BindingOperations.GetBindingExpression(parent, entry.Property);
                    expression.UpdateSource();

                    if (expression.HasError)
                    {
                        valid = false;
                    }
                }
            }
        }

        // Validate all the bindings on the children
        System.Collections.IEnumerable children = LogicalTreeHelper.GetChildren(parent);
        foreach (object obj in children)
        {
            if (obj is DependencyObject)
            {
                DependencyObject child = (DependencyObject)obj;
                if (!IsValid(child)) { valid = false; }
            }
        }
        return valid;
    }

Dean의 위대한 LINQ 구조화 외에도 Code를 의존성 관점을위한 확장으로 포장하는 것이 재미있었습니다.

public static bool IsValid(this DependencyObject instance)
{
   // Validate recursivly
   return !Validation.GetHasError(instance) &&  LogicalTreeHelper.GetChildren(instance).OfType<DependencyObject>().All(child => child.IsValid());
}

이것은 재사용을 고려할 때 매우 좋습니다.

나는 작은 최적화를 제공 할 것입니다.

동일한 컨트롤을 통해 여러 번이 작업을 수행하면 위의 코드를 추가하여 실제로 유효성 검사 규칙이있는 컨트롤 목록을 유지할 수 있습니다. 그런 다음 유효성을 확인해야 할 때마다 전체 시각적 트리 대신 해당 컨트롤을 살펴보십시오. 그러한 컨트롤이 많으면 훨씬 나은 것으로 판명 될 것입니다.

여기에 있습니다 도서관 WPF의 양식 검증 용. 여기 Nuget 패키지.

견본:

<Border BorderBrush="{Binding Path=(validationScope:Scope.HasErrors),
                              Converter={local:BoolToBrushConverter},
                              ElementName=Form}"
        BorderThickness="1">
    <StackPanel x:Name="Form" validationScope:Scope.ForInputTypes="{x:Static validationScope:InputTypeCollection.Default}">
        <TextBox Text="{Binding SomeProperty}" />
        <TextBox Text="{Binding SomeOtherProperty}" />
    </StackPanel>
</Border>

아이디어는 첨부 된 속성을 통해 유효성 검사 범위를 정의하여 추적 할 입력 제어를 알려주는 것입니다. 그런 다음 우리는 할 수 있습니다 :

<ItemsControl ItemsSource="{Binding Path=(validationScope:Scope.Errors),
                                    ElementName=Form}">
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="{x:Type ValidationError}">
            <TextBlock Foreground="Red"
                       Text="{Binding ErrorContent}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

모든 컨트롤 트리를 재귀 적으로 반복하고 첨부 된 속성 유효성 검사를 확인한 후 첫 번째 부분에 집중할 수 있습니다.

이미 작성된 많은 솔루션을 사용할 수 있습니다. 이것 예제와 자세한 정보를위한 스레드

당신은 다음에 관심이있을 수 있습니다 책도서관 샘플 적용 WAF(WPF 애플리케이션 프레임워크).WPF에서 유효성 검사를 사용하는 방법과 유효성 검사 오류가 있을 때 저장 버튼을 제어하는 ​​방법을 보여줍니다.

답변 형태 Aogan은 유효성 검사 규칙을 명시 적으로 반복하는 대신 expression.UpdateSource():

if (BindingOperations.IsDataBound(parent, entry.Property))
{
    Binding binding = BindingOperations.GetBinding(parent, entry.Property);
    if (binding.ValidationRules.Count > 0)
    {
        BindingExpression expression 
            = BindingOperations.GetBindingExpression(parent, entry.Property);
        expression.UpdateSource();

        if (expression.HasError) valid = false;
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top