Перехватывать преобразование Silverlight DatePicker из текста в DateTime

StackOverflow https://stackoverflow.com/questions/1601481

Вопрос

Я хочу, чтобы DatePicker преобразовал следующие фрагменты текста в DateTime (отображается в международном формате), чтобы мои клиенты могли написать дату в DatePicker текстовое поле быстрее, так что это не просто DateTime.Parse я буду использовать:

"3" to 2009-10-03
"14" to 2009-10-14
"1403" to 2009-03-14
"140310" to 2010-03-14
"14032010" to 2010-03-14

Я пробовал разные способы сделать это, но они не работают. Я пытался связать DatePicker.Text / DatePicker.SelectedDate / DatePicker.DisplayDate с пользовательским преобразователем значений. Но это не работает, потому что DatePicker уже обработал текст, прежде чем я доберусь до текста.

Я также пытался преобразовать в DatePicker TextBox.LostFocus следующим образом:

public class CustomDatePicker : DatePicker
{
    private DatePickerTextBox textBox;

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

        textBox = this.GetTemplateChild("TextBox") as DatePickerTextBox;

        if (textBox != null)
            textBox.LostFocus += textBox_LostFocus;
    }

    void textBox_LostFocus(object sender, RoutedEventArgs e)
    {
        if (textBox == null) return;

        DateTime result;

        // This is my method for converting my special cases, 
        // parses d, dd, mm, ddmm, ddmmyy, ddmmyyyy
        if (textBox.Text.TryParseShortcut(out result)) 
        {
            // I have also tried with 
            // this.SelectedDate/DisplayDate = result;
            textBox.Text = result.ToString("dd/MM/yyyy"); 
            return;
        }

        if (DateTime.TryParse(textBox.Text, out result))
        {
            // I have also tried with 
            // this.SelectedDate/DisplayDate = result;
            textBox.Text = result.ToString("dd/MM/yyyy");
            return; 
        }
    }
}

Есть идеи?

Это было полезно?

Решение

Если вы используете Binding для привязки данных к вашему DatePicker, вы можете использовать ValueConverter.

Быстрый пример конвертера дат:

public class CustomDateValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is string)
        {
            string dateValue = (string)value;
            switch (dateValue.Length)
            {
                case 1:
                case 2:
                    return new DateTime(DateTime.Now.Year, DateTime.Now.Month, System.Convert.ToInt32(dateValue)).ToString("dd/MM/yyyy");
                //...
            }
        }

        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        // here you should implement your logic to convert your value back.

        return value;
    }
}

Элемент управления DatePickerTextBox в XAML:

<controls:DatePickerTextBox Text="{Binding Path=Data, Mode=TwoWay, Converter={StaticResource CustomDateValueConverter}}" />

DatePickerTextBox в cs:

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();
        DataContext = new MyData() { Data = "3" };

        _textBox.LostFocus += (se, ea) =>
            {
                _textBox.DataContext = 
                    new MyData() { Data = _textBox.Text };
            };
}

public class MyData
{
    public string Data { get; set; }
}

Я только что создал класс MyData для использования в качестве данных в этом примере.

Другие советы

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

private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    if (this._textBox != null)
    {
        this.SetValueNoCallback(TextProperty, this._textBox.Text);
    }
}

Таким образом, к тому времени, когда вы доберетесь до потерянного кода фокуса, значение уже будет установлено. Мне удалось обойти это, используя подклассы, но так как TextChanged обрабатывает каждое изменение, я не уверен, что ваш метод синтаксического анализа будет работать (так как, как только вы нажмете 1 число, он будет изменен на дату).

public class CustomDatePicker : DatePicker
{
    private TextBox textBox; 

    public override void OnApplyTemplate() 
    { 
        base.OnApplyTemplate(); 
        textBox = this.GetTemplateChild("TextBox") as TextBox; 

        if (textBox != null)
            textBox.TextChanged += textBox_TextChanged;
    }

    void textBox_TextChanged(object sender, TextChangedEventArgs e)
    {  
        if (textBox.Text == "now")             
        {                
            // I have also tried with 
            // this.SelectedDate/DisplayDate = result;                
            textBox.Text = DateTime.Now.ToShortDateString();                 
        }  
    }
}

Это работает для меня, так как ничего не меняется, пока не будет написано все слово, но в вашем случае это, вероятно, не сработает.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top