C# 基于WPF中现有数据的验证

C# 基于WPF中现有数据的验证,c#,wpf,data-binding,validationrule,C#,Wpf,Data Binding,Validationrule,我需要创建一个验证节点,如果输入的值已经存在,该节点将返回一个错误。我有GUI,其中的项目可以设置名称。我想强制这些名称是唯一的 因此,对于每个验证,我需要以下两个参数: 所有项的所有名称的列表,或者一些谓词,它们将告诉我一个名称存在 当前项名称,将其从上述验证中排除(将名称更改为相同的值不应是错误) 数据上下文如下所示(仅用于说明的界面): 我尝试使用下面的答案进行正确绑定,但随后出现错误: 无法在类型为MyProject\u Validation\u UniqueNameRule\u 9

我需要创建一个验证节点,如果输入的值已经存在,该节点将返回一个错误。我有GUI,其中的项目可以设置名称。我想强制这些名称是唯一的

因此,对于每个验证,我需要以下两个参数:

  • 所有项的所有名称的列表,或者一些谓词,它们将告诉我一个名称存在
  • 当前项名称,将其从上述验证中排除(将名称更改为相同的值不应是错误)
数据上下文如下所示(仅用于说明的界面):

我尝试使用下面的答案进行正确绑定,但随后出现错误:

无法在类型为
MyProject\u Validation\u UniqueNameRule\u 9\u 468654的“MyName”属性上设置“Binding”。只能对DependencyObject的DependencyProperty设置“绑定”

看起来根本不支持绑定


那么,我该如何将这两个变量放在一起,以便验证规则可以访问这两个变量呢?

由于验证规则如何落在可视化树上的性质,绑定正在失败,这可能是您所怀疑的

绑定上还有其他风格的(请参阅该文档中的属性部分)


最终需要父节点,这里有一个用于可能相关的样式:

<vmvalidation:UniqueNameRule 
                MyName="{Binding Name, RelativeSource={RelativeSource TemplatedParent}}"/>

由于验证规则如何落在可视化树上的性质,绑定失败,这可能是您所怀疑的

绑定上还有其他风格的(请参阅该文档中的属性部分)


最终需要父节点,这里有一个用于可能相关的样式:

<vmvalidation:UniqueNameRule 
                MyName="{Binding Name, RelativeSource={RelativeSource TemplatedParent}}"/>

绑定可能是正确的,但我得到了这个错误:“不能在类型为
MyProject\u Validation\u UniqueNameRule\u 9\u 468654
的'MyName'属性上设置'binding'。只能在DependencyObject的DependencyProperty上设置'binding'。所以我猜绑定不是这里的解决方案。我能做什么?在阅读您的评论时,它提醒我一个绑定问题,该问题也有类似的失败,但必须使用
TwoWay
binding来解决。。。。也许你可以创建一个小的测试项目来演示这个问题,并在这里提供给我们尝试。如果创建它还需要其他任何东西的话,那么它可能会揭示为什么这个绑定不同于其他类型的绑定。我现在很好奇这是否是最简单的方法。绑定可能是正确的,但我得到了这个错误:“不能在类型为
MyProject\u Validation\u UniqueNameRule\u 9\u 468654
的'MyName'属性上设置'binding'。只能在DependencyObject的DependencyProperty上设置'binding'所以我猜绑定不是这里的解决方案。我能做什么?在阅读您的评论时,它提醒我一个绑定问题,该问题也有类似的失败,但必须使用
TwoWay
binding来解决。。。。也许你可以创建一个小的测试项目来演示这个问题,并在这里提供给我们尝试。如果创建它还需要其他任何东西的话,那么它可能会揭示为什么这个绑定不同于其他类型的绑定。我只是好奇这是不是最简单的方法。
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows.Controls;

namespace MyApp.Validation
{
  public class UniqueNameRule : ValidationRule
  {
    public IEnumerable<string> ExistingNames { get; set; }

    public string MyName { get; set; }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
      if(value is string newValue)
      {
        // name changed
        if(!value.Equals(MyName))
        {
          if(ExistingNames.Contains(newValue))
          {
            return new ValidationResult(false, "Name already exists!");
          }
        }
        return new ValidationResult(true, null);
      }
      else
      {
        return new ValidationResult(false, "Invalid value type. Is this validator valid for the given field?");
      }
    }
  }
}
<Binding.ValidationRules>
  <vmvalidation:UniqueNameRule MyName="{Binding Name}"  />
</Binding.ValidationRules>

{Binding Path=DataContext.ItemNames, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}
<vmvalidation:UniqueNameRule 
                MyName="{Binding Name, RelativeSource={RelativeSource TemplatedParent}}"/>
<vmvalidation:UniqueNameRule 
    MyName="{Binding Name, RelativeSource={RelativeSource Mode=FindAncestor, 
                                                          AncestorType={x:Type TextBox}}"/>