I need to create a validation node that will return an error if value entered already exists. I have GUI with items that can have their name set. I want to enforce the names to be unique.
So for each validation, I need following two parameters:
- List of all names of all items, or some predicate that will tell me a name exists
- Current items name, to exclude it from the above validation (changing the name to the same value should not be an error)
The data contexts look like this (just the interface for illustration):
class AppMainContext
{
public IEnumerable<string> ItemNames {get;}
public Item SelectedItem {get;}
}
class Item
{
public string Name {get;}
}
The field in WPF looks like this and its parent is bound to `{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>
The validator looks like this:
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?");
}
}
}
}
I tried to at least bind current name to the validator. The text box already exists in current items data context, so a correct binding would be:
<Binding.ValidationRules>
<vmvalidation:UniqueNameRule MyName="{Binding Name}" />
</Binding.ValidationRules>
Except that this gives an error:
The member
MyName
is not recognized or is not accessible.
The list of all items is in the windows data context, accessible through ItemNames
. I suppose it could be accessed like this:
{Binding Path=DataContext.ItemNames, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}
I tried correct binding using an answer below, but I then get an error:
A 'Binding' cannot be set on the 'MyName' property of type
MyProject_Validation_UniqueNameRule_9_468654
. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
Looks like bindings are not supported at all.
So how can I put this together, so that the validation rule can access both of these variables?