This question already has an answer here:
Can't bind CalendarDatePicker to a model in Xaml UWP
(1 answer)
Closed 5 years ago.
I'm triying to bind a DateTime from the ViewModel to a calendarDatePicker, but it doesn't work. i've tried in a textbox and works.
This part works:
<TextBox Text="{Binding MyDate}" ></TextBox>
And this doesn't:
<CalendarDatePicker Date="{Binding MyDate}" />
This question was previously answered here on MSDN.
Per the article, you could use a Converter to convert the binding to a DateTimeOffset. The converter may look something like the following, which comes from this post (referenced by the MSDN answer):
public class DateTimeToDateTimeOffsetConverter : 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 DateTimeOffset.MinValue;
}
}
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;
}
}
}
Related
We have a API service that we are updating and we converted some date objects from strings to DateTime objects. In the old code we tested the string if it would parse to a data time or not. If it was a bad formatted string, it would assign DateTime.Min and continue on. Now customers are sending in bad dates and it blows up since the serialization happens outside our code (MVC Controller). I am trying to find some way that when serializing a DateTime object, if it can not parse it, it just returns DateTime.Min instead of blowing up the call.
Here is the response from the API Call.
{
"date": [
"Could not convert string to DateTime: Invalid Date. Path 'date', line 3, position 24."
]
}
===== UPDATE =====
I finally found somewhere that recommended a custom JsonConverter. I finally got something that works, but there is little out there so if there is something I could do better I am all ears.
Custom Converter
public class DateConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
try
{
return DateTime.Parse(reader.Value.ToString());
}
catch (Exception ex)
{
return DateTime.MinValue;
}
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateTime);
}
}
DTO Class
public class Request
{
[JsonConverter(typeof(SafeDateConverter))]
public DateTime Date { get; set; }
}
Another approach introduce another property on deserialized class of type DateTime? and leave original string property as it is.
public class Request
{
public string Date { get; set; }
private DateTime? _parsedDate;
[JsonIgnore]
public DateTime? ParsedDate
{
get { return _parsedDate; }
set
{
if (DateTime.TryParse(value, out DateTime parsed)
{
_parsedDate = parsed;
return;
}
_parsed = null;
}
}
}
But having custom serializer looks better, because you need change nothing in the code which already uses deserialized object.
Suggestion:
Do not use try ... catch for serializing bad formatted dates, there is DateTime.TryParse method which will do this without throwing exceptions.
And if it is not late, you can use Nullable<DateTime> instead of having DateTime.Min as "not existing" value.
Apparantly in Xamarin forms there isn't an option to use FallbackValue or TargetNullValue, how could I use a converter to accomplish the task?
I'm looking to have visibility default to null if the data binding object is null.
NullConverter.cs
public class NullConverter : IMarkupExtension, IValueConverter
{
public object IsNullValue { get; set; }
public object IsNotNullValue { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? IsNullValue : IsNotNullValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
XAML
<Entry Text="{Binding WhateverProperty}" />
<Button IsVisible="{Binding WhateverProperty, Converter={local:NullConverter IsNullValue=False, IsNotNullValue=True}}" />
For my testing, WhateverProperty was a string that was originally set to null, whenever I update the Entry, the button shows up. Of course, you can use it with any type of property.
How to set credit card number format In xaml
Like
1234-1234-1234-1234
This can be easily achieved by using Value converters.
public class CreditCardNumberValueConverter : IValueConverter
{
public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var builder = new StringBuilder(Regex.Replace(value.ToString(), #"\D", ""));
foreach (var i in Enumerable.Range(0, builder.Length / 4).Reverse())
builder.Insert(4*i + 4, " ");
return builder.ToString().Trim();
}
public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Regex.Replace(value.ToString(), #"\D", "");
}
}
After initialising this in Styles.cs, you can apply it to the Text property of the control in XAML as:
Text="{Binding CardNo, Converter={StaticResource CreditCardNumberValueConverter}}"
Likewise, Phone numbers too can also be formatted.
<Label Text="{Binding YourVmPropertyNameHere StringFormat='{0:0000-0000-0000-0000}'}">
This is assuming that your view model has already converted the number to an integer and set it to the property "YourVmPropertyNameHere".
I´m trying to databind the current culture with the right enum set in a Dictionary in Xamarin Forms XAML.
I get a list of Events from the server that contain the Dictionary properties containing the languages that I´m going to use to show the right language depending on what Culture is set.
public class Event
{
// Having problem binding with the right CultureInfo í the Dictionary
public Dictionary<Language, string> Title { get; set; }
}
// Types of languages that I could use to pick the right language string
public enum Language
{
English = 0,
German
}
// Just a basic view-model
public class EventsViewModel
{
public EventsViewModel()
{
}
//James Montemagno´s MVVM Helper https://github.com/jamesmontemagno/mvvm-helpers
public ObservableRangeCollection<Event> Events { get; } = new ObservableRangeCollection<Event>();
}
// Just a basic Content page
public partial class EventsPage : ContentPage
{
public EventsPage ()
{
InitializeComponent();
BindingContext = new EventsViewModel(Navigation);
}
}
Now I just need the XAML to bind the right value in the Dictionary based on the enum/culture...
I have tried doing this "semi-manual" by using a Converter and checking the CultureInfo and picking the right value but for some reason I just can´t get the Converters to fire up.
I also tried to mix up IValueConverter and IMarkupExtension but no good.
Ok I found out what was missing from the Converter method I had been trying to use. I was missing the ConvertParameter and that was the reason the Convert method did´t fire.
So what I did.
1.
I put this line into the App.xaml to be able to access it from anywhere
<converters:LanguageDictionaryEnumConverter x:Key="LanguageConverter" />
2.
Then I put this one into my page. I do not use the parameter at all. (But I would if I could pass in my settings culture object)
<Label Text="{Binding Title,Converter={StaticResource LanguageConverter},ConverterParameter={x:Static dataObjects:Language.English}}" />
3.
And then I implemented a crude dictionary-language-enum converter/picker that chooses the right language string to send back to the page.
public class LanguageDictionaryEnumConverter : IMarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var dic = (Dictionary<Language, string>)value;
var cultInMySettings= Settings.Current.GetCultureInfoOrDefault;
switch (cultInMySettings.Name)
{
case "de-DE":
return dic[Language.German];
case "en-US":
return dic[Language.English];
default:
return dic[Language.English];
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
But if you have some better way to databind the values straight to the XAML in some other way I want to hear about it and will choose that answer over this one for sure if its more elegant.
I'm trying to use the new dateTimePicker for Windows 8.1:
<DatePicker HorizontalAlignment="Left" Margin="401,245,0,0" Grid.Row="1"
VerticalAlignment="Top" Width="352" Date="{Binding personSingle.personDOB,Mode=TwoWay}"/>
When ever I change the date I don't get the value that I chose when I look at value for personDOB.
personDOB is of type DateTimeOffset
What do I need to do get the value that I choose?
Update:
<DatePicker x:Name="dtPick" HorizontalAlignment="Left" Margin="401,245,0,0" Grid.Row="1"
VerticalAlignment="Top" Width="352" DataContext="{Binding personSingle}"
Date="{Binding personSingle.personDOB.Date,Mode=TwoWay}"/>
I found the answer from this link:
http://bretstateham.com/binding-to-the-new-xaml-datepicker-and-timepicker-controls-to-the-same-datetime-value/
You need to write a converter to get this to work appropriately:
public class DateTimeToDateTimeOffsetConverter : 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 DateTimeOffset.MinValue;
}
}
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;
}
}
}
As it was explained to me, it is better to throw an exception when converting then to use a default.
public class DateTimeToDateTimeOffsetConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return new DateTimeOffset((DateTime)value);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return ((DateTimeOffset)value).DateTime;
}
}