Date picker validation WPF - wpf

How to apply validations to WPF datepicker toolkit? I want it to error out if invalid date is selected and in some case I have Arrival and Departure dates, so I want to validate it to see that the arrival date is not later than the departure date.

It seems a year above date picker validation was a problem. Anyway, now it works.
I am not a WPF specialist, bu I'll try to give you an idea
write a validation rule
public class DateExpiredRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
DateTime orderDate = (DateTime)value;
return new ValidationResult(orderDate < DateTime.Now, "Please, enter date before Now()");
}
}
then you can attach it to datepicker
<!-- since validation works hand by hand with binding,
I use hidden datepicker as binding source -->
<WPFToolkit:DatePicker Name="dateProvider" Visibility="Collapsed">
</WPFToolkit:DatePicker>
<WPFToolkit:DatePicker Name="notExpired">
<WPFToolkit:DatePicker.SelectedDate>
<Binding ElementName="dateProvider" Path="SelectedDate" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:DateExpiredRule/>
</Binding.ValidationRules>
</Binding>
</WPFToolkit:DatePicker.SelectedDate>
</WPFToolkit:DatePicker>
specify control template when validation error occurs. By default validation error changes border color. I used additional tooltip when mouse is over control.
source code
About 'picker to picker' validation.
I know that one can use custom properties in validation rules (see AgeRangeRule in msdn example)
Maybe you should use this feature like this
<local:MaxDateRule MaxDate="{Binding ElementName=DepartureDatePicker, Path=SelectedDate" />
but in order to apply binding you need to make MaxDate a DependencyProperty .. you should definetly ask a guru ;)
Instead of highlighting you should consider intercepting the datepicker value change (via some kind of datepicker 'onchange' event) and accept or reject the change.

Related

DatePicker WPF + accepting dd/mm/yyyy format [duplicate]

Simplified Question:
I have a datepicker in WPF. I enter a value 30/10/1983 in the textbox of the datepicker. I need the value to be posted back to my viewmodel, where in I have bound it to a DateTime? property.
Is there any way I can achieve this. mm/dd/yyyy format triggers a postback but not dd/mm/yyyy.
The DatePicker code is as below.
<DatePicker Grid.Row="2" Name="inputDate"
Text="{Binding BirthDate,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
>
</DatePicker>
The view model property is as below.
private DateTime? birthDate;
public DateTime? BirthDate
{
get
{
return this.birthDate;
}
set
{
this.birthDate = value;
OnPropertyChanged("BirthDate");
}
}
I enter a value 10/10 into the datepicker textbox, the setter gets called with a value, but the moment I enter an entire date 30/10/1983, I still have the view model property which is equal to NULL.
I have changed the Format to English-UnitedKingdom, in the calendar settings, and my CurrentCulture reflects en-GB appropriately.
Original Question:
I have a datetimepicker control in WPF, which I have bound the text property to a Nullable DateTime in the view model.
The problem I am facing is when I enter a value in the format MM/dd/yyyy, I do get a value postback in the view model, indicating the new value.
But when I enter the value in dd/MM/yyyy format, I do not get a notification in the view model and the value is lost. The bound propertyin the view model is null.
The short date format is the one which I have specified in the calendar settings & dateFormat, within which for a short date format I provide the entry as "dd/MM/yyyy".
Could someone please help me with this scenario where in I accept date in dd/MM/yyyy format, and I do not want to hardcode, I wish to pick up the short date format from the calendar settings and also, I wish to recieve the updated value in the view model too.
The problem is related that a not valid date will not set with a correct value your ViewModel DateTime property. So, you can intercept it and convert correctly with a CONVERTER.
An example:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string strValue = System.Convert.ToString(value);
DateTime resultDateTime;
if (DateTime.TryParse(strValue, out resultDateTime))
{
return resultDateTime;
}
return value;
}
And your XAML code will be like:
<DatePicker
Text="{Binding BirthDate,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
SelectedDate="{Binding RelativeSource={RelativeSource Self},Path=Text,
Converter={StaticResource DateConverter}}"
/>

WPF Validation Errors

In my current projet, I have to deal with data validation in a WPF form. My form is in a DataTemplate in a ResourceDictionnary. I can save and load the data from my form thanks to two buttons, which serialize and deserialize the data (through two DelegateCommand).
If one field of my form is empty or invalid, the save button is disable. A field is checked everytime it changes thanks to the UpdateSourceTrigger propertie. That's why I need to know in my C# code if a field is invalid to update my save command.
Currently, I use the ExceptionValidationRule in my XAML Binding and I wonder if it's a good pratice. I can't implement a ValidationRule because I need to know in my C# code if a field is invalid, to update the save command (enable or disable the save button).
<TextBox>
<Binding Path="Contact.FirstName" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ExceptionValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox>
In this blog, we can read :
Raising exceptions in the Setters is not a very good approach since those properties are also set by code and sometimes it is ok to temporarily leave them with error values.
I already read this post but I can't use it, my TextBox are in a DataTemplate and I can't use them in my C# code.
So, I wonder if I should change my Data Validation and don't use the ExceptionValidationRule.
Thank you blindmeis, your idea was good.
IDataErrorInfo seems to be better than the ExceptionValidationException and it works.
Here is an example which match my project :
IDataErrorInfo sample
It doesn't use the DelegateCommand but is simple enough to be modified. Your model has to implement IDataErrorInfo :
public class Contact : IDataErrorInfo
{
public string Error
{
get { throw new NotImplementedException(); }
}
public string Name { get; set; }
public string this[string property]
{
get
{
string result = null;
if (property== "Name")
{
if (string.IsNullOrEmpty(Name) || Name.Length < 3)
result = "Please enter a Name";
}
return result;
}
}
}
In the XAML code, don't forget to change the Binding :
<TextBox>
<Binding Path="Contact.Name" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True" NotifyOnValidationError="True"/>
</TextBox>

Timepicker Updatesourcetrigger=propertychanged doesn't change value

I'm hosting a WPF usercontrol in a windows form
In the wpf user control I am using a timepicker from wpfToolkit.extended
If I use the up or downkeys or just enter a time in the textfield the source is not updated allthough I am using Updatesourcetrigger = propertychanged.
When I select a time in the dropdrownlist everything works the way it should.
This is the namespace of the toolkit.
xmlns:xctk="clr-namespace:Xceed.Wpf.Toolkit;assembly=WPFToolkit.Extended"
This is the xaml for the timepicker
<xctk:TimePicker Format="LongTime" TimeInterval="00:15:00.000" Value="{Binding Path=StartTime, UpdateSourceTrigger=PropertyChanged}" ></xctk:TimePicker>
If I click outside the WPFusercontrol without changing the focus to another control in the wpf usercontrol first. The Binded time is not updated.
Any idea how I can fix this?
Found a solution for this problem:
I've given the TimePicker a name (In this case 'tpFrom') then I've used the TextBoxBase.TextChanged event on the TimePicker.
This is what the Xaml looks like now:
<xctk:TimePicker Name="tpFrom" Format="LongTime" TextBoxBase.TextChanged="TimePicker_TextChanged" TimeInterval="00:15:00.000" Value="{Binding Path=StartTime, UpdateSourceTrigger=PropertyChanged}"></xctk:TimePicker>
In the code behind in our eventhandler we'll put the focus on our timepicker.
private void TimePicker_TextChanged(object sender, TextChangedEventArgs e)
{
tpFrom.Focus();
}
Now everytime the text changes, the value changes as well and the problem is solved :-)
Does the TimePicker have a Text property? If so, try binding to that instead.
I think this behavior might be to prevent you from binding to a bad datetime as you type. I would guess that when focus is lost it tries to set the property and does error checking. If it did this while you typed it would constantly be changing the value anytime you make a change (say delete a character).
Is there something specific you are trying to do as you type?

SilverLight required datepicker validation

I have an SL4 user control. It contains a DatePicker. The control exposes a DateTime dependency property (not nullable, because it's a required field). I've bound the SelectedDate of the DatePicker (which is a Nullable<DateTime>) to this DateTime property of {RelativeSource Self}, as two-way. This binding works except when I enter a null date in the DatePicker. The binding is set up with ValidatesOnExceptions, so the border of the DatePicker turns to red, but in the tooltip it says "input is not in a correct format". But it should say that the field is required.
I tried a custom IValueConverter which throwed an exception (ValidationException, FormatException, InvalidOperationException. etc.) with a custom text, but they all ended up unhandled.
I know my control could implement INotifyDataErrorInfo, but the problem is that the null value doesn't even make it into my control, since my DateTime is not nullable, so there's nothing to validate.
I could easily do this thing without any binding at all. Or by binding to a hidden Nullable<DateTime> property in my control, validating that this property is not null, and exposing another DateTime property. Or by providing a ValueConverter which converts a null to DateTime.MinValue or something.
But these methods all seem like workarounds and I'd love a better solution. What's the best way to handle this?
Submitted to Connect, votes appreciated.
https://connect.microsoft.com/VisualStudio/feedback/details/661318/the-binding-engine-doesnt-handle-exceptions-from-a-converter
You've basically got to make the value you're binding your DatePicker to a nullable DateTime even though null isn't a valid value.
Then you'll just have to rely on your validation logic to ensure that your application never allows the value to be processed/stored/whateverd while it's null.

Applying a validation rule on a binding to display a validation result only on the UI

I am applying a validation rule to the binding on a text box. I have got the validation right from the UI perspective in that I see the error message on the tool tip and have the error template applied too(Just the usual red border).
However, the validation that I have to display is not super critical and is sufficient to just be displayed on the UI. The problem that I have with the binding is that the validation rule prevents updates on the source object once a validation rule gets violated I want the source to get updated with exactly the content of the textbox.
Is there a way to display the error template on the UI without affecting the bound source.
My code looks something like
<TextBox Name="texBox">
<TextBox.Text>
<Binding Path="ProductCode" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<jas:RegexValidationRule
RegexText="^[A-Z]{3}\.[0-9]{3}$"
ErrorMessage="Invalid product code. (Examples: ABC.123 xyz.789)"
RegexOptions="IgnoreCase"
/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
This happens because if a validation error or other type of error occurs at any time during the binding process, the process is halted.I guess you have to set the ValidationStep property to UpdatedValue
Sample:
<jas:RegexValidationRule ValidationStep="UpdatedValue"
RegexText="^[A-Z]{3}\.[0-9]{3}$"
ErrorMessage="Invalid product code. (Examples: ABC.123 xyz.789)"
RegexOptions="IgnoreCase"
/>
Please check the "Validation Process" section in Data Binding Overview.This will give you good overview of what you are tying to do
You could try looking into IDataErrorInfo instead. Then you'll get the validation in your backing class (ViewModel) so the Text in the displayed TextBox will be in sync with the backing property. In your case it will look something like this
<TextBox Name="texBox">
<TextBox.Text>
<Binding Path="ProductCode" UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
</TextBox>
In the datacontext backing class
public class YourClass : IDataErrorInfo
{
//...
#region IDataErrorInfo Members
public string Error
{
get { throw new NotImplementedException(); }
}
public string this[string columnName]
{
get
{
string result = null;
if (columnName == "ProductCode")
{
// Do your Regex Validation.
if (regexValidationFailed)
{
result = "Validation Error Text/Tooltip";
}
}
if (columnName == "SomeOtherProperty)
//...
return result;
}
}
#endregion
}

Resources