I am trying to create a validation rule for a given control (in this scenario, it is the TextBox).
I am not able to obtain a successful Binding to the property of an object, although appropriate steps were taken: ValidationRule and DepedencyProperty are taken advantage of.
Kindly find code below. A side note is that "Is Required" in the custom Validation class is always False, unless I explicitly set the value in the XAML (no Binding, as per "Is Ranged" parameter).
Any tips and suggestions are appreciated.
Thank you in advance :)
XAML Code:
<TextBox Style="{StaticResource ValidationError}" LostFocus="ForceValidationCheck"
Visibility="{Binding Type, Converter={StaticResource Visibility}, ConverterParameter='Number'}"
IsEnabled="{Binding RelativeSource={x:Static RelativeSource.Self}, Converter={StaticResource IsEnabled}}">
<TextBox.Text>
<Binding Path="Value">
<Binding.ValidationRules>
<validation:NumericValidation>
<validation:NumericValidation.Dependency>
<validation:NumericDependency IsRequired="{Binding Path=IsRequired}" IsRanged="True" Min="5"/>
</validation:NumericValidation.Dependency>
</validation:NumericValidation>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Validation Class:
public NumericDependency Dependency { get; set; }
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
isRequired = Dependency.IsRequired;
}
Validation Dependency Class:
public static readonly DependencyProperty IsRequiredProperty =
DependencyProperty.Register("IsRequired", typeof(bool), typeof(NumericDependency), new UIPropertyMetadata(default(bool)));
public bool IsRequired
{
get
{
return (bool) GetValue(IsRequiredProperty);
}
set
{
SetValue(IsRequiredProperty, value);
}
}
You can use a proxy. It will allow you to bind a Property to your ValidationRule.
Here is a code sample that may help you :
<Utils:Proxy In="{Binding IsRequired, Mode=OneWay,UpdateSourceTrigger=PropertyChanged}" Out="{Binding ElementName=numericValidationRule, Path=IsRequired}" />
<TextBox>
<TextBox.Text>
<Binding Path="Value">
<Binding.ValidationRules>
<NumericValidation x:Name="numericValidationRule" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
IsRequired is always false because the "Dependency" object is not part of the logical tree, so you can not use ElementName or DataContext as source for internal data binding.
The solution to this problem is based on the following Thomas Levesque's article: http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
You must create a class that inherits "Freezable" and declares a Data dependency property. The interesting feature of a Freezable class is that Freezable objects can inherit the DataContext even when they’re not in the visual or logical tree:
public class BindingProxy : Freezable
{
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}
You can then declare an instance of this class in the resources of you textbox, and bind the Data property to the current DataContext:
<TextBox.Resources>
<local:BindingProxy x:Key="proxy" Data="{Binding}"/>
<TextBox.Resources/>
Finally, specify this BindingProxy object as the Source for the binding:
<validation:NumericDependency IsRequired="{Binding Source={StaticResource proxy} Path=Data.IsRequired}" IsRanged="True" Min="5"/>
Note that the binding path must be prefixed with "Data" since since the path is now relative to the BindingProxy object.
There is another way of implementing the Validation of the Controls. However, I would still like to know how to solve my initial issue, so any help is appreciated.
Another way is implementing the IDataErrorInfo interface of the model.
Example:
public string this[string columnName]
{
get
{
if (string.Equals(columnName, "Value", StringComparison.CurrentCultureIgnoreCase))
{
string value = Convert.ToString(Value);
if (string.IsNullOrEmpty(value) && IsRequired)
{
return ValidationMessage.RequiredValue;
}
}
return string.Empty;
}
}
"Is Required" in the custom Validation class is always False, because it is not set. and false is the default value for bool.
From http://www.codeproject.com/Articles/18678/Attaching-a-Virtual-Branch-to-the-Logical-Tree-in
ValidationRule does not even have a DataContext property since it does not derive from FrameworkElement!
Note that IntegerContainer is a FrameworkElement, not a Dependency Object.
来源:https://stackoverflow.com/questions/13725223/wpf-dependencyproperty-validation-binding-to-the-object-property