简体   繁体   中英

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

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;
    }
}

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM