我需要创建一个验证节点,如果输入的值已经存在,它将返回错误。我有带有可以设置名称的项目的 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 上设置“绑定”。
看起来根本不支持绑定。
那么我怎样才能把它放在一起,以便验证规则可以访问这两个变量呢?