c# - 基于 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 上设置“绑定”。
看起来根本不支持绑定。
那么我怎样才能把它放在一起,以便验证规则可以访问这两个变量呢?
解决方案
由于验证规则如何落在可视化树上的性质,绑定失败,这可能是您所怀疑的。
在绑定上还有其他风格的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}}"/>
推荐阅读
- python - 如何将 Pandas 中的非零条目转换为带有列表的 dict?
- android - 单击后突出显示 ActionMenuView 中的菜单项
- c# - 实体框架 (MVC) - 为具有受保护属性的模型创建控制器时出现问题
- python - 如何编写带循环的函数
- mysql - 我需要为同一列使用 2 个索引还是一个就足够了?
- excel - excels“文件来源”的熊猫等价物
- css - css grid - 让网格向下而不是跨越五个相等的列
- php - 如何在 PHP 中安排定期更新 MySQL 数据库?
- javascript - 在 tensorflow JavaScript 中使用posenet时内存泄漏
- groovy - 在 groovy 中,如何返回零填充范围?