Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Auto correction behaviour on XAML bound datetime objects since .NET 4.0?

While bringing an application from .NET 3.5 to .NET 4.0 I've run into this peculiar issue.

(culture is nl-BE)

I bind a TextBox like this (in XAML) to a DateTime value with an UpdateSourceTrigger on PropertyChanged (LostFocus works as expected but as-you-type validation is required):

<TextBox Height="23" Margin="146,0,105,97.04" Name="txb_Geboortedatum" VerticalAlignment="Bottom">
        <TextBox.Text>
            <Binding Path="Geboortedatum" StringFormat="d" 
                     UpdateSourceTrigger="PropertyChanged">
                <Binding.ValidationRules>
                    <ExceptionValidationRule />
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
</TextBox>

Now when the contents of this textbox is (for example) 10/12/2000 and I want to edit it to be 09/03/1981 some obnoxious auto-correction occurs when i put the cursor at the end of 2000 and start 'backspacing' away the year value (when only the first digit ('2') of '2000' is left the value automatically - including cursor jump - changes to 2002 again). Can I disable this auto-correction?

I can't seem to find what specifically introduced this behaviour. The same 'problem' also occurs with FormatString=c for currency values.

What I've tried so far:

  1. Changing the FormatString to something more explicit like {0}{dd/MM/yyyy} (same problem: starts auto-correcting when there are 2 digits for year left).
  2. Disabling the following snippet I've added to my App.xaml.cs:

    FrameworkElement.LanguageProperty.OverrideMetadata(
        typeof(FrameworkElement), 
        new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(
            CultureInfo.CurrentCulture.IetfLanguageTag)));
    

The reasoning for this snippet to be included in the first place: have a look at this link.

Am i missing something obvious here? I can't reproduce this in 3.5. Do I really have to roll my own ValueConverters for getting this to work properly? That looks like a step back from StringFormat which was introduced in 3.5 sp 1.

Output from DateTimeFormatInfo.CurrentInfo.GetAllDateTimePatterns('d') does looks slightly different, nothing that would immediately explain the behaviour though (probably unrelated):

.NET 3.5        .NET 4.0

d/MM/yyyy       d/MM/yyyy
d/MM/yy         d/MM/yy
dd-MM-yy        dd-MM-yy
dd.MM.yy        dd.MM.yy
yyyy-MM-dd      dd.MMM.yyyy
                yyyy-MM-dd

like image 850
ChristopheD Avatar asked Jun 14 '11 21:06

ChristopheD


2 Answers

I ended up using something like this for now, but I would be extremely interested in other approaches for solving the problem above:

public class CustomDateTimeConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, 
                          CultureInfo culture)
    {
        if (value == null) { return ""; }
        DateTime dt;
        if (DateTime.TryParse(value.ToString(), CultureInfo.CurrentCulture, 
                              DateTimeStyles.None, out dt))
        {
            return dt.ToShortDateString();
        }
        return "";
    }

    public object ConvertBack(object value, Type targettype, object parameter, 
                              CultureInfo culture)
    {
        if (value == null || value.ToString().Trim().Length==0) { return null; }
        string frmt = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;
        DateTime dt;
        if (DateTime.TryParseExact(value.ToString(), frmt, 
                                   CultureInfo.CurrentCulture, 
                                   DateTimeStyles.None, out dt))
        {
            return dt;
        }
        return DependencyProperty.UnsetValue;
    }
}
like image 182
ChristopheD Avatar answered Nov 13 '22 02:11

ChristopheD


Well, this behavior is 'normal' if you auto-correct on PropertyChanged. When you start backspacing, the value passed to the DateTime constructor is :

Screen >> DateTime ( '|' is the cursor placement before each backspace)

10-12-2000| >> DateTime(200,12,10) >> 10-12-0200

10-12-020|0 >> DateTime(020,12,10) >> 10-12-020 

10-12-00|20  >> DateTime(020,12,10) >> 10-12-020 

10-12-0|20 >> DateTime(20,12,10) >> 10-12-2020

(I think this can vary with your culture because of the yy-mm-dd string format)

tough i dont quite get why new DateTime(20,12,10) guive the year 2020 for me on the textbox. When i use DateTime.Parse(20,12,10) it guive me 2012-10-20 (yyyy-mm-dd). Ther must be some kind of automatique conversion or parsing that we dont have control over unless we use a custom ValueConvertor

I think a custom converter is a good way to go if you absolutly need 'as-you-type validation', else OnLostFocus works well as you said.

Btw, my culture is en-US

like image 27
Gab Avatar answered Nov 13 '22 00:11

Gab