Форматирование Datepicker в британский формат, когда уже Великобритания - PullRequest
0 голосов
/ 29 апреля 2018

В 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"/>

Если я выберу дату из всплывающего календаря, тогда дата будет отображаться нормально. Однако, если я ввожу дату, она предполагает, что я ввожу в формате США и конвертирую в Великобританию.

т.е. если я хочу напечатать 5 июня 2018 года, например, 05.06.2008, при нажатии на поле это внезапно становится 05.06.2008.

У меня вопрос: есть ли способ определить, каким будет формат ввода, а не просто как должна выглядеть дата после выбора даты?

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Вы можете создать пользовательский 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));
        }
    }
}
0 голосов
/ 29 апреля 2018

Кажется, что StringFormat не влияет на значение, полученное из пользовательского ввода.

Из документов :

Получает или задает строку, которая определяет, как форматировать привязку, если она отображает связанное значение в виде строки.

Я считаю, что есть более надежное решение, но я не нашел ничего, что могло бы решить эту проблему без использования конвертеров.

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, передавая формат в качестве аргумента.

Но есть недостаток - вы можете работать только с одним форматом - дд / мм / гггг. Если вы введете что-то вроде 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'}"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...