【问题标题】:Can you replace DatePickerTextBox with a different TextBox in DatePicker and still get the validation functionality?您可以在 DatePicker 中用不同的 TextBox 替换 DatePickerTextBox 并仍然获得验证功能吗?
【发布时间】:2014-06-04 17:56:22
【问题描述】:

我替换了DatePicker 的控制模板中的DatePickerTextBox,它不再确保输入文本的有效日期值。我也用普通的DatePickerTextBox 测试了不同的字符串,它没有验证它们,所以它一定是DatePickerTextBoxDatePicker 之间的某种交互。有没有办法在控件模板中与不是DatePickerTextBox 的不同TextBox 控件进行交互,还是我必须在我自己的自定义控件中重新创建该验证?

【问题讨论】:

    标签: wpf validation datepicker controltemplate


    【解决方案1】:

    带答案的简短说明:

    在自定义TextBox控件的OnApplyTemplate方法中,我添加了:

    public override void OnApplyTemplate()
    {
        LostFocus += OnLostFocus;
    
        base.OnApplyTemplate();
    }
    

    然后是方法:

    private void OnLostFocus(object sender, RoutedEventArgs e)
    {
        if (!Text.Equals(oldText))
        {
            DateTime d;
            if (!DateTime.TryParse(Text, out d))
            {
                Text = oldText;
            }
        }
        oldText = Text;
    }
    

    详细解释为什么替换后它在控件模板中不起作用 DatePickerTextBox

    我在reference source 中四处寻找,发现了以下内容:

    DatePickerOnApplyTemplate 方法中,添加了一些处理程序,特别是针对DatePickerTextBox,如果找不到,它将不适用(这解释了为什么DatePickerTextBox 不验证它自己的,要么 - DatePicker 添加处理程序,而不是 DatePickerTextBox):

    _textBox = GetTemplateChild(ElementTextBox) as DatePickerTextBox;
    
    if (this.SelectedDate == null)
    {
        SetWaterMarkText();
    }
    
    if (_textBox != null)
    {
        _textBox.AddHandler(TextBox.KeyDownEvent, new KeyEventHandler(TextBox_KeyDown), true);
        _textBox.AddHandler(TextBox.TextChangedEvent, new TextChangedEventHandler(TextBox_TextChanged), true);
        _textBox.AddHandler(TextBox.LostFocusEvent, new RoutedEventHandler(TextBox_LostFocus), true);
    
        if (this.SelectedDate == null)
        {
            if (!string.IsNullOrEmpty(this._defaultText))
            {
                _textBox.Text = this._defaultText;
                SetSelectedDate();
            }
        }
        else
        {
            _textBox.Text = this.DateTimeToString((DateTime)this.SelectedDate);
        }
    }
    

    所以,追踪它(有趣的部分来了)...

    private void TextBox_LostFocus(object sender, RoutedEventArgs e)
    {
        SetSelectedDate();
    }
    

    然后:

    private void SetSelectedDate()
    {
        if (this._textBox != null)
        {
            if (!string.IsNullOrEmpty(this._textBox.Text))
            {
                string s = this._textBox.Text;
    
                if (this.SelectedDate != null)
                {
                    // If the string value of the SelectedDate and the TextBox string value are equal,
                    // we do not parse the string again
                    // if we do an extra parse, we lose data in M/d/yy format
                    // ex: SelectedDate = DateTime(1008,12,19) but when "12/19/08" is parsed it is interpreted as DateTime(2008,12,19)
                    string selectedDate = DateTimeToString(this.SelectedDate.Value);
    
                    if (string.Compare(selectedDate, s, StringComparison.Ordinal) == 0)
                    {
                        return;
                    }
                }
    
                DateTime? d = SetTextBoxValue(s);
                if (!this.SelectedDate.Equals(d))
                {
                    this.SetCurrentValueInternal(SelectedDateProperty, d);
                    this.SetCurrentValueInternal(DisplayDateProperty, d);
                }
            }
            else
            {
                if (this.SelectedDate.HasValue)
                {
                    this.SetCurrentValueInternal(SelectedDateProperty, (DateTime?)null);
                }
            }
        }
        else
        {
            DateTime? d = SetTextBoxValue(_defaultText);
            if (!this.SelectedDate.Equals(d))
            {
                this.SetCurrentValueInternal(SelectedDateProperty, d);
            }
        }
    }
    

    重要的是打电话给SetTextBoxValue

    private DateTime? SetTextBoxValue(string s)
    {
        if (string.IsNullOrEmpty(s))
        {
            SafeSetText(s);
            return this.SelectedDate;
        }
        else
        {
            DateTime? d = ParseText(s);
    
            if (d != null)
            {
                SafeSetText(this.DateTimeToString((DateTime)d));
                return d;
            }
            else
            {
                // If parse error:
                // TextBox should have the latest valid selecteddate value:
                if (this.SelectedDate != null)
                {
                    string newtext = this.DateTimeToString((DateTime)this.SelectedDate);
                    SafeSetText(newtext);
                    return this.SelectedDate;
                }
                else
                {
                    SetWaterMarkText();
                    return null;
                }
            }
        }
    }
    

    重要的是拨打ParseText

    private DateTime? ParseText(string text)
    {
        DateTime newSelectedDate;
    
        // TryParse is not used in order to be able to pass the exception to the TextParseError event
        try
        {
            newSelectedDate = DateTime.Parse(text, DateTimeHelper.GetDateFormat(DateTimeHelper.GetCulture(this)));
    
            if (Calendar.IsValidDateSelection(this._calendar, newSelectedDate))
            {
                return newSelectedDate;
            }
            else
            {
                DatePickerDateValidationErrorEventArgs dateValidationError = new DatePickerDateValidationErrorEventArgs(new ArgumentOutOfRangeException("text", SR.Get(SRID.Calendar_OnSelectedDateChanged_InvalidValue)), text);
                OnDateValidationError(dateValidationError);
    
                if (dateValidationError.ThrowException)
                {
                    throw dateValidationError.Exception;
                }
            }
        }
        catch (FormatException ex)
        {
            DatePickerDateValidationErrorEventArgs textParseError = new DatePickerDateValidationErrorEventArgs(ex, text);
            OnDateValidationError(textParseError);
    
            if (textParseError.ThrowException && textParseError.Exception != null)
            {
                throw textParseError.Exception;
            }
        }
    
        return null;
    }
    

    最后两种方法具有我正在寻找的验证。如果ParseText 返回null,则SetTextBoxValue 将文本框中的值恢复为之前的值。因为DatePicker 是添加处理程序的控件,所以您不会在DatePicker 之外获得验证。由于DatePicker 专门寻找名为"PART_TextBox"DatePickerTextBox(即ElementTextBox 字符串),所以必须使用DatePickerTextBox,否则将不会应用处理程序(因为_textbox 将是@ 987654351@).

    【讨论】:

      猜你喜欢
      • 2010-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-19
      • 1970-01-01
      相关资源
      最近更新 更多