首页 > 解决方案 > 基于 WPF 中现有数据的验证

问题描述

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

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

数据上下文如下所示(仅用于说明的界面):

class AppMainContext
{
  public IEnumerable<string> ItemNames {get;}
  public Item SelectedItem {get;}
}

class Item 
{
  public string Name {get;}
}

WPF 中的字段如下所示,其父级绑定到`{SelectedItem}:

<DockPanel DockPanel.Dock="Top">
  <Label Content="Name: "/>
  <TextBox DockPanel.Dock="Top">
    <TextBox.Text>
      <Binding Path="Name" UpdateSourceTrigger="PropertyChanged">
        <Binding.ValidationRules>
          <vmvalidation:UniqueNameRule  />
        </Binding.ValidationRules>
      </Binding>
    </TextBox.Text>
  </TextBox>
</DockPanel>

验证器如下所示:

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>

除了这给出了一个错误:

该成员MyName未被识别或不可访问。

所有项目的列表都在 windows 数据上下文中,可通过ItemNames. 我想它可以像这样访问:

{Binding Path=DataContext.ItemNames, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}

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

不能在 'MyName' 类型的属性上设置 'Binding' MyProject_Validation_UniqueNameRule_9_468654。只能在 DependencyObject 的 DependencyProperty 上设置“绑定”。

看起来根本不支持绑定。

那么我怎样才能把它放在一起,以便验证规则可以访问这两个变量呢?

标签: c#wpfdata-bindingvalidationrule

解决方案


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

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


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

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

或者沿着链条向上工作,而不是x:Type Window如何更有可能绑定到父级,例如x:Type TextBox

<vmvalidation:UniqueNameRule 
    MyName="{Binding Name, RelativeSource={RelativeSource Mode=FindAncestor, 
                                                          AncestorType={x:Type TextBox}}"/>

推荐阅读