Reputation: 1647
I am new to WPF. The form's data context includes a StartTime
and an EndTime
field (using MVVM), which I have successfully bound to their own text boxes. I am trying to create a validation to check that a new user-entered StartTime
is before the EndTime
value. The following code does not seem to bind the EndTime
field to the validation parameter Maximum
.
XAML:
<TextBox>
<TextBox.Text>
<Binding Path="StartTime" UpdateSourceTrigger="LostFocus" StringFormat="{}{0:hh}:{0:mm}">
<Binding.ValidationRules>
<local:ValidateTime>
<local:ValidateTime.Maximum>
<local:ValidationParameter Parameter="{Binding EndTime, StringFormat=hh\\:mm}" />
</local:ValidateTime.Maximum>
</local:ValidateTime>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
View model:
public class ValidationParameter : DependencyObject
{
public static readonly DependencyProperty ParameterProperty = DependencyProperty.Register(
"Parameter",
typeof(string),
typeof(ValidationParameter),
new FrameworkPropertyMetadata(null));
public string Parameter
{
get { return (string)GetValue(ParameterProperty); }
set { SetValue(ParameterProperty, value); }
}
}
public class ValidateTime : ValidationRule
{
private TimeSpan _Minimum = new TimeSpan(0, 0, 0);
private TimeSpan _Maximum = new TimeSpan(23, 59, 9);
private ValidationParameter _MinimumProperty;
private ValidationParameter _MaximumProperty;
public ValidationParameter Minimum
{
get
{
return _MinimumProperty;
}
set
{
TimeSpan ts;
if (TimeSpan.TryParse(value.Parameter, out ts))
{
_Minimum = ts;
_MinimumProperty = value;
}
}
}
public ValidationParameter Maximum
{
get
{
return _MaximumProperty;
}
set
{
TimeSpan ts;
if (TimeSpan.TryParse(value.Parameter, out ts))
{
_Maximum = ts;
_MaximumProperty = value;
}
}
}
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
string formattedValue = value.ToString();
if (Regex.IsMatch(formattedValue, @"^\d{4}$"))
{
formattedValue = string.Format("{0}:{1}", formattedValue.Substring(0, 2), formattedValue.Substring(2, 2));
}
TimeSpan convertedValue;
if (TimeSpan.TryParseExact(formattedValue, "g", System.Globalization.CultureInfo.CurrentCulture, out convertedValue))
{
if (convertedValue > _Maximum)
{
return new ValidationResult(false, string.Format("Time must be before {0}.", _Maximum.ToString("g")));
}
else if (convertedValue < _Minimum)
{
return new ValidationResult(false, string.Format("Time must be after {0}.", _Minimum.ToString("g")));
}
return ValidationResult.ValidResult;
}
else
{
return new ValidationResult(false, string.Format("'{0}' is not a valid time entry.", value.ToString()));
}
}
}
The code works if I set the parameter to a static value like the following, but I need this validation to be dynamic:
<local:ValidateTime.Maximum>
<local:ValidationParameter Parameter="12:00" />
</local:ValidateTime.Maximum>
Upvotes: 1
Views: 2766
Reputation: 1175
In my case
<local:RangeValidation ValidationStep="UpdatedValue"/>
helped. So you pass the DependencyObject as value(.dataitem) including your Datacontext and have no need to pass a parameter to the Validation. BR, Daniel
BTW credits not on mee, just found it but can't remember who gave the hint :)
Upvotes: 0
Reputation: 184376
You probably need to work around the fact that ValidationRules
are not in the visual or logical trees, which causes bindings to DataContext
, ElementName
and RelativeSource
to fail.
Upvotes: 0
Reputation: 778
First you want to give your TextBox a name like so:
<TextBox Name="StartTime"/>
Then you set the parameter for validation like so:
<local:ValidateTime.Maximum>
<local:ValidationParameter Parameter="{Binding ElementName=StartTime, Path=Text" />
</local:ValidateTime.Maximum>
If the validation works like you said you should be all set.
You can do the same thing with your EndTime TextBox if you want as well assuming you write a working rule for it
Upvotes: 0