Datepicker ValidationRules from code behind: validation rule not called on user input - c#

I'm creating a wpf UserControl that contains a Datepicker. This datepicker is generated from code behind in c#.
public partial class EditorDatePicker : UserControl
{
public EditorDatePicker(TagEntry element, bool isTagPresent)
{
InitializeComponent();
// datepicker binding and validation
Binding binding = new Binding();
binding.Path = new PropertyPath("DateDict[" + element.ParentTag + element.ChildTag + "]");
binding.NotifyOnValidationError = true;
binding.ValidatesOnDataErrors = true;
binding.Converter = new DateTimeConverter();
binding.Mode = BindingMode.TwoWay;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidationRules.Add(new DateValidationRule());
this.datePicker.SetBinding(DatePicker.SelectedDateProperty, binding);
}
class DateTimeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
{
try
{
DateTime test = (DateTime)value;
string date = test.ToString("d/M/yyyy");
return (date);
}
catch
{
return null;
}
}
return null;
}
The fact is that the validation rule is never called when I manualy enter a date in the DatePicker text field (But it's called when using the datepicker). The only thing I got is a FormatException on lost focus.
Any idea? Thanx.

One possibility is to use converter:
public class DateTimeNullConverter : MarkupExtension, IValueConverter
{
public override object ProvideValue(IServiceProvider serviceProvider) => this;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is DateTime)
return value.ToString();
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var text = value as string;
DateTime result;
if (text != null && DateTime.TryParse(text, out result))
return result;
return null;
}
}
You can use it like this to bind to public DateTime? DateTime property:
<TextBox Text="{Binding DateTime, Converter={local:DateTimeNullConverter}}" />
ConvertBack will be called on lost focus.

Related

IValueConverter Using Lookup Collection

I am using a converter like this:
public class BreedConverter : IValueConverter
{
static ObservableCollection<Breed_> Breeds = Breed_.GetBreeds();
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null && Breeds.Count > 0)
{
short breedID = (short)value;
Breed_ breed = Breeds.Single(s => s.BreedID == breedID);
return (string)breed.Breed;
}
else
return "";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
The Breeds collection is retrieved from a SQL Server database. I want to retrieve it once and then use it to do the conversion. I don't want to go to the database each and every time I need to convert.
Is there a better way to do this, e.g. ResourceDictionary (which I don't know how to use in this scenario, since I'm still a noob)?
This is what I have been able to get to work. As #Darthchai mentioned, I have created the collection in the class/window. However, I cannot figure out how to use INotifyPropertyChanged to let the specific TextBlock know to do the conversion. I am a noob, after all. :) What I was able to do - and I don't know if this is the right approach - was to use the Loaded event of the TextBlock to do the conversion. here is the code:
private void BreedTextBlock_Loaded(object sender, RoutedEventArgs e)
{
TextBlock textBlock = (TextBlock)sender;
if (textBlock != null && Breeds.Count > 0)
{
try
{
short breedID = short.Parse(textBlock.Text);
Breed_ breed = Breeds.Single(s => s.BreedID == breedID);
textBlock.Text = (string)breed.Breed;
}
catch
{
}
}
return;
}

How to clear the date bound to a CalendarDatePicker if certain conditions occur in UWP?

I have a CalendarDatePicker whose Date property is bound to a converter.
I don't want it to show the date if the date is default(01-01-0001)
My code
class DateTimeToCalendarDateTimeOffsetConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
try
{
DateTime date = (DateTime)value;
return new DateTimeOffset(date);
}
catch (Exception ex)
{
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
try
{
DateTimeOffset dto = (DateTimeOffset)value;
return dto.DateTime;
}
catch (Exception ex)
{
return DateTime.MinValue;
}
}
}
But by default it set's todays date.
What value can I set to clear the date?
From the discussion we had earlier, I think you wanted to set the the Date of the CalendarDatePicker according to the value which is got from a server, but at first this value is set to "0001-01-01" by default.
So you can do it like this:
<Page.Resources>
<local:DateTimeToCalendarDateTimeOffsetConverter x:Key="cvt" />
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<CalendarDatePicker x:Name="picker" Date="{x:Bind Path=dateTime,Converter={StaticResource cvt}, Mode=TwoWay}" />
</Grid>
code behind:
private DateTime dateTime;
public MainPage()
{
this.InitializeComponent();
dateTime = new DateTime(0001, 01, 01);
}
This variable dateTime is fake by me and is set in the code behind, and the converter is like this:
public class DateTimeToCalendarDateTimeOffsetConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var date = (DateTime)value;
if (date == new DateTime(0001, 01, 01))
{
return null;
}
return new DateTimeOffset?(date);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
var dto = (DateTimeOffset)value;
return dto.DateTime;
}
}
But be aware that the Date is constrained by MinDate and MaxDate, if Date is smaller than MinDate, the value is set to MinDate. If the Date is greater than MaxDate, the value is set to MaxDate. So if you set the date here for example "0010-01-02", and your MinDate is set to "2000-01-01", when return this date in your Converter, the CalendarDatePicker will show "01/01/2000".
For more information about this control, you can refer to CalendarDatePicker class.

Custom date format for textbox

Related: Binding 3 textboxes together; same DateTime different format
I have three textboxes, all are supposed to be bound together with the same date. Two of them have normal string formats. The third one has a specific format of yyyy,jjj/HHmmss. I can't figure out how to bind this textbox to the custom format I have, and make it so if I change any of the date values in it, the other textboxes will update and vice versa.
private DateTime _dateInViewModel;
public DateTime DateInViewModel
{
get { return _dateInViewModel; }
set
{
_dateInViewModel = value;
NotifyPropertyChanged("DateInViewModel");
}
}
<TextBox Name="SDate1" Text="{Binding DateInViewModel, StringFormat='MM/dd/yyyy'}" />
<TextBox Name="SDate2" Text="{Binding DateInViewModel}" />
<TextBox Name="STime1" Text="{Binding DateInViewModel, StringFormat='hh:mm:ss'}" />
The custom format can be made like:
format = String.Format("{0},{1}/{2}",
DateInViewModel.Year,
DateInViewModel.DayOfYear.ToString("d3"),
DateInViewModel.ToString("HHmmss"));
Right now, only SDate1 and STime1 bind to each other properly and update when the other is changed.
I made a converter. It properly updates SDate2 when SDate1 and STime1 are changed, but doesn't work when editing SDate2 to update the others.
public class DateTimeConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
{
DateTime test = (DateTime)value;
string date = String.Format("{0},{1}/{2}",
test.Year,
test.DayOfYear.ToString("d3"),
test.ToString("HHmmss"));
return (date);
}
return string.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
You need to set the convert back in the converter. This is just an example but you need to parse the value back into original source so other binds can be updated.
since your format is {0},{1}/{2} then you need to split it back up and reconstruct the intended date.
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return null;
string strValue = value.ToString();
if (string.IsNullOrEmpty(strValue) && targetType == typeof(DateTime?))
{
return null;
}
else if (string.IsNullOrEmpty(strValue))
{
return DateTime.MinValue;
}
//year,dayOfYear/Time(HHmmss)
var parts = strValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 2) {
var year = parts[0];
parts = parts[1].Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 2) {
var days = parts[0];
var time = parts[1];
var date = new DateTime(int.Parse(year), 1, 1)
.AddDays(int.Parse(days))
.Add(TimeSpan.Parse(time));
return date;
}
}
DateTime resultDateTime;
return DateTime.TryParse(strValue, out resultDateTime) ? resultDateTime : value;
}

How to leave DateTimePicker object blank (Select a date) on load when DateTime is null (01/01/0001) but populate when there is a value?

I'm trying to get a DateTimePicker object to populate with the default text (Select a date) when it doesn't get any date back from the database. If there is a date in the database, the field will populate with that date.
I wroting code that has a two way bind on SelectedDate option to a DateTime property on in the code-behind. It works properly and populates the field with 01/01/0001 since that is the null of DateTime objects. I've tried to changing it to a OneWayToSource and just bind the date if it is greater than 01/01/0001 but it puts a redbox around the object if it doesn't get a date.
Any suggestion?
Thanks for the help everyone! Here is the solution that I found.
[ValueConversion(typeof(DateTime), typeof(DateTime))]
class DateTimeNullConverter: IValueConverter
{
public object Convert (object value, Type targetType, object parameter, Culture culture)
{
if (value != null)
{
DateTime dateTime = (DateTime)value;
if (dateTime.Year.ToString == "1")
return null;
else
return dateTime;
}
else
{
return null;
}
}
public object ConvertBack (object value, Type targetType, object parameter, Culture culture)
{
DateTime convertDateTime;
if (value == null)
{
convertDateTime = new DateTime();
}
else
{
convertDateTime = (DateTime) value;
}
return convertDateTime;
}
}
Create a DateBlankConverter converter that binds to the same control:
<DatePicker x:Name="DatePickerInstance"
Visibility="{Binding ElementName=DatePickerInstance,
Converter={StaticResource DateBlankConverter}, ConverterParameter={Binding Date}}"/>
And inside the converter check if the date is null to hide or show the DatePicker, or change the property you need.
You could try with some code in the setter and getter of your property
private DateTime? _date;
public DateTime? Date
{
get
{
if (null == _date)
{
//Set some initial value
//or just return some default value without setting the property
}
return _date;
}
set
{
if (value != _date)
{
_date = value;
this.OnPropertyChanged("Date");
}
}
}
Thanks for the help everyone! Here is the solution that I found.
[ValueConversion(typeof(DateTime), typeof(DateTime))]
class DateTimeNullConverter: IValueConverter
{
public object Convert (object value, Type targetType, object parameter, Culture culture)
{
if (value != null)
{
DateTime dateTime = (DateTime)value;
if (dateTime.Year.ToString == "1")
return null;
else
return dateTime;
}
else
{
return null;
}
}
public object ConvertBack (object value, Type targetType, object parameter, Culture culture)
{
DateTime convertDateTime;
if (value == null)
{
convertDateTime = new DateTime();
}
else
{
convertDateTime = (DateTime) value;
}
return convertDateTime;
}
}

FormatString on WPF-DataGrid has no effect

i have a small problem with FormatString in my WPF-DataGrid. I use DataGridTextColumn for the column. My DataSource is a IList<IDictionary<string, string>>
My problem is, that if i set StringFormat, it doesn't have any effect on the column.
This is my binding code:
cColumn.Binding = new Binding("[" + Config.InternName.ToLower() + "]");
And this is how i set my FormatString:
#region [Date-Time Formating]
if (Config.DateTimeFormat.Trim() != "")
{
string cDateTimeFormat = Config.DateTimeFormat.Trim();
(cColumn.Binding as Binding).StringFormat = cDateTimeFormat;
}
#endregion
I have tried a lot DateTime-StringFomrats, but nothing solve my problem.
Thank you!
Here is my solution:
I can't simple use FormatString, without binding a datetime. So i wrote an IValueconverter:
public class StringDateTimeValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
DateTime cOutDateTime = DateTime.Now;
if (DateTime.TryParse(value.ToString(), out cOutDateTime))
{
return cOutDateTime;
}
else
{
return DependencyProperty.UnsetValue;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.ToString();
}
}

Categories

Resources