WPF 项目控件项目模板验证

发布于 2024-11-19 21:26:10 字数 75 浏览 2 评论 0原文

有没有办法确定 ItemsControl 是否有任何带有验证错误的子控件?我想将此值(布尔值)绑定到按钮上的 IsEnabled 属性。

Is there a way to determine if an ItemsControl has any child controls with validation errors? I would like to bind this value (boolean) to the IsEnabled property on a Button.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

永不分离 2024-11-26 21:26:10

我最近使用了之前的 SO 答案中的代码检测 WPF 验证错误< /a> 正是为此取得了良好的效果。

我有一个包含 DataGrid 的用户控件。用户控件公开一个包含 getter 的 IsValid 属性,该属性仅调用作为 DependencyObject 传入 DataGrid

public class MyControl : UserControl
{
    public bool IsValid
    {
        get { return Validator.IsValid(MyDataGrid); }
    }
}

的静态 IsValid 函数:然后可以通过CanExecute 您绑定到要启用/禁用的按钮的命令的功能。

我链接到的代码的唯一问题是它实际上评估了绑定上的验证,这意味着一旦您运行它,任何技术上无效但尚未无效的字段(即用户可能尚未输入该字段中的任何数据(因为他们还没有到达)现在都将处于无效状态 - 我还没有找到避免或减轻这种情况的方法。


编辑:

这是一个更新版本,不会像我之前提到的那样使控件无效。我只是注释掉/稍微更改了一些行,但将所有内容保留在那里,以便您可以看到差异。请注意,这也应该执行得更快,因为您将在发现第一个无效绑定时退出。

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;
                    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))
        {
            //valid = false;
            return false;
        }
    }

    //return valid;
    return true;
}

I've recently used the code from this previous SO answer Detecting WPF Validation Errors to good effect for exactly this.

I have a user control which contains a DataGrid. The usercontrol exposes a IsValid property which contains a getter, that simply calls the static IsValid function passing in the DataGrid as the DependencyObject:

public class MyControl : UserControl
{
    public bool IsValid
    {
        get { return Validator.IsValid(MyDataGrid); }
    }
}

The control's IsValid property can then be checked by the CanExecute function of the command you bind to the button you want to enable/disable.

My only issue with the code that i linked to was that it actually evaluates the validations on the bindings, this means as soon as you run it any field that is technically invalid but hasn't yet been invalidated (i.e. the user may not have entered any data in that field yet because they haven't got to it) will now be in an invalid state - i haven't yet looked at a way to avoid or mitigate this.


Edit:

here is an updated version that doesn't invalidate the controls as i mentioned previously. I've simply commented out/slightly changed some lines but left everything in there so you can see the difference. Note that this should also perform faster as you will be exiting the moment you find the first invalid binding.

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;
                    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))
        {
            //valid = false;
            return false;
        }
    }

    //return valid;
    return true;
}
酷炫老祖宗 2024-11-26 21:26:10

我不知道为什么,slugter 的答案对我不起作用(LocalValueEnumerator 返回了一些属性,但从未返回绑定的属性,例如 Text)。

我设法让它与此代码一起工作(源自这个答案):

public static 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) &&
        GetVisualTreeChildren(obj)
        .OfType<DependencyObject>()
        .All(child => IsValid(child));
}

//VisualTreeHelper don't have a method to get all the children of a visual object
private static IEnumerable GetVisualTreeChildren(DependencyObject parent)
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
        yield return VisualTreeHelper.GetChild(parent, i);
}

I don't know why, slugter's answer didn't work for me (LocalValueEnumerator returned some properties but never the binded ones, like Text).

I managed to get it working with this code (derived from this answer):

public static 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) &&
        GetVisualTreeChildren(obj)
        .OfType<DependencyObject>()
        .All(child => IsValid(child));
}

//VisualTreeHelper don't have a method to get all the children of a visual object
private static IEnumerable GetVisualTreeChildren(DependencyObject parent)
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
        yield return VisualTreeHelper.GetChild(parent, i);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文