基于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}}}

我试着用下面的答案纠正绑定,但后来我得到了一个错误:

不能在类型为MyProject_Validation_UniqueNameRule_9_468654的"MyName"属性上设置"Binding"。只能在DependencyObject的DependencyProperty上设置"Binding"。

看起来根本不支持绑定。

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

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

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}}"/>

相关内容

  • 没有找到相关文章

最新更新