已经英国时,Datepicker格式化为英国格式

时间:2018-04-29 15:36:57

标签: wpf vb.net xaml

在WPF中,我有一个带有以下文本样式的日期选择器:

<Style TargetType="{x:Type DatePickerTextBox}">
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate>
                <TextBox x:Name="PART_TextBox"
                Text="{Binding Path=SelectedDate, StringFormat='dd/MM/yyyy', 
                  RelativeSource={RelativeSource AncestorType={x:Type DatePicker}}}"
                         Foreground="white"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

datepicker项目本身看起来像这样

<DatePicker x:Name="datepickShowDate" Grid.Column="1" Foreground="white" CalendarStyle="{StaticResource styleCalendar}" 
    FontSize="14" HorizontalAlignment="Left" Height="30" 
    VerticalAlignment="Top" Width="139"/>

如果我从弹出日历中选择日期,则日期显示正常。 但是,如果我输入日期,它似乎假设我以美国格式输入并转换为英国。

即。如果我想在2018年6月5日输入像05/06/2018一样,点击该字段时它突然变成06/05/2018。

我的问题是,有没有什么方法可以定义输入格式,而不仅仅是日期选择后的日期应该是什么样的?

2 个答案:

答案 0 :(得分:2)

似乎StringFormat不会影响从用户输入收到的值。

来自docs

  

获取或设置一个字符串,指定如何格式化绑定   将绑定值显示为字符串。

我相信有更强大的解决方案,但如果不使用转换器,我找不到任何可以解决此问题的方法。

public class DateTimeConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var dateTime = (DateTime?)value;
        if (!dateTime.HasValue)
        {
            return string.Empty;
        }
        var format = (string)parameter;
        return dateTime.Value.ToString(format, culture);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var format = (string)parameter;
        DateTime dateTime;
        if (DateTime.TryParseExact((string)value, format, culture, DateTimeStyles.None, out dateTime))
        {
            return dateTime;
        }
        return DependencyProperty.UnsetValue;
    }
}

这里的技巧是在ConvertBack方法中使用DateTime.TryParseExact,将格式作为参数传递。

但是有一个缺点 - 你只能使用一种格式--dd / MM / yyyy。如果您输入类似2018-04-29的内容 - 它将无效。

要使用此转换器,您需要在资源中声明它:

<local:DateTimeConverter x:Key="converter"/>

并使用ConverterParameter代替StringFormat(尽管您可以使用StringFormat,但会在应用转换器后使用它):

Text="{Binding Path=SelectedDate, 
      RelativeSource={RelativeSource AncestorType={x:Type DatePicker}},
      Converter={StaticResource converter}, 
      ConverterParameter='dd/MM/yyyy'}"

答案 1 :(得分:1)

您可以创建自定义DatePicker

public class UkDatePicker : DatePicker
{
    private DatePickerTextBox _datePickerTextBox;
    private const string _shortDatePattern = "dd/MM/yyyy";
    private readonly CultureInfo _formatProvider = new CultureInfo("en-GB");

    public UkDatePicker()
    {
        Language = XmlLanguage.GetLanguage(_formatProvider.IetfLanguageTag);
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        _datePickerTextBox = Template.FindName("PART_TextBox", this) as DatePickerTextBox;
        if (_datePickerTextBox != null)
        {
            _datePickerTextBox.SetBinding(TextBox.TextProperty, new Binding(nameof(DatePicker.SelectedDate))
            {
                RelativeSource = new RelativeSource() { AncestorType = typeof(DatePicker) },
                StringFormat = _shortDatePattern
            });
            _datePickerTextBox.TextChanged += dptb_TextChanged;
        }
    }

    private void dptb_TextChanged(object sender, TextChangedEventArgs e)
    {
        DateTime dt;
        if (DateTime.TryParseExact(_datePickerTextBox.Text, _shortDatePattern, _formatProvider,
            DateTimeStyles.None, out dt))
        {
            SelectedDate = dt;
        }
    }
}

示例XAML:

<local:UkDatePicker DockPanel.Dock="Top" SelectedDate="{Binding Date}"/>

<StackPanel Orientation="Horizontal" Margin="0 10 0 0">
    <TextBlock Text="Selected Date: " FontSize="16" FontWeight="Bold"/>
    <TextBlock Text="{Binding Date, StringFormat=dd/MM/yyyy}" FontSize="16"/>
</StackPanel>

查看型号:

public class ViewModel : INotifyPropertyChanged
{
    private DateTime? _date;
    public DateTime? Date
    {
        get { return _date; }
        set { _date = value; NotifyPropertyChanged(); }
    }


    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}