2014-01-16 54 views
0

對於我的WPF應用程序,我創建了基於TextBox的幾個自定義控件。這些包括NumericTextBox,WatermarkTextBox和ReturnTextBox。MaxLength屬性在我的自定義文本框中打破

數字和水印從繼承自TextBox的ReturnTextBox繼承。

當我使用我的任何自定義文本框時,它們都很棒。一個問題似乎是NumericTextBox和MaxLength屬性。該屬性現在被忽略,不起作用。在我的任何自定義控件中沒有任何代碼覆蓋或混淆MaxLength屬性。

當我使用的MaxLength我ReturnTextBox,它的工作原理就像你所期望的:

<ui:ReturnTextBox MaxLength="35" Width="500" Background="LightYellow" Text="{Binding BrRptCorpName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" TabIndex="2" /> 

然而,當我使用屬性上我的NumericTextBox它被忽略並不起作用:

<ui:NumericTextBox MaxLength="9" Background="LightYellow" Text="{Binding BrRptAmt, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" TabIndex="1" /> 

任何人都可以幫我弄清楚爲什麼MaxLength停止工作?是否因爲NumericTextBox不直接從TextBox繼承?我應該重寫ReturnTextBox中的MaxLength屬性,以便Numeric可以使用它?

的代碼已更新

ReturnTextBox類:

public class ReturnTextBox : TextBox 
{ 
    static ReturnTextBox() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(ReturnTextBox), new FrameworkPropertyMetadata(typeof(ReturnTextBox))); 
    } 

    protected override void OnPreviewKeyDown(KeyEventArgs e) 
    { 
     if (e.Key == Key.Return) 
     { 
      e.Handled = true; 
      MoveFocus(new TraversalRequest(FocusNavigationDirection.Next)); 
     } 
     base.OnPreviewKeyDown(e); 
    } 
} 

NumericTextBox

public class NumericTextBox : ReturnTextBox 
{ 
    #region Base Class Overrides 

    static NumericTextBox() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericTextBox), new FrameworkPropertyMetadata(typeof(NumericTextBox))); 
    } 

    public static readonly DependencyProperty TypeProperty = DependencyProperty.Register("Type", 
      typeof(NumericType), typeof(NumericTextBox), new UIPropertyMetadata (NumericType.Integer)); 
    public static readonly DependencyProperty SelectAllOnGotFocusProperty = DependencyProperty.Register("SelectAllOnGotFocus", 
      typeof(bool), typeof(NumericTextBox), new PropertyMetadata(false)); 

    [Description("Numeric Type of the TextBox"), Category("Common Properties")] 
    public NumericType Type 
    { 
     get { return (NumericType)GetValue(TypeProperty); } 
     set { SetValue(TypeProperty, value); } 
    } 

    [Description("Select text on focus"), Category("Common Properties")] 
    public bool SelectAllOnGotFocus 
    { 
     get 
     { 
      return (bool)GetValue(SelectAllOnGotFocusProperty); 
     } 
     set 
     { 
      SetValue(SelectAllOnGotFocusProperty, value); 
     } 
    } 

    protected override void OnPreviewTextInput(TextCompositionEventArgs e) 
    { 
     Text = ValidateValue(Type, Text); 
     bool isValid = IsSymbolValid(Type, e.Text); 
     e.Handled = !isValid; 
     if (isValid) 
     { 
      int caret = CaretIndex; 
      string text = Text; 
      bool textInserted = false; 
      int selectionLength = 0; 

      if (SelectionLength > 0) 
      { 
       text = text.Substring(0, SelectionStart) + text.Substring(SelectionStart + SelectionLength); 
       caret = SelectionStart; 
      } 
      if (e.Text == NumberFormatInfo.CurrentInfo.NumberDecimalSeparator) 
      { 
       while (true) 
       { 
        int ind = text.IndexOf(NumberFormatInfo.CurrentInfo.NumberDecimalSeparator); 
        if (ind == -1) 
         break; 
        text = text.Substring(0, ind) + text.Substring(ind + 1); 
        if (caret > ind) 
         caret--; 
       } 
       if (caret == 0) 
       { 
        text = "0" + text; 
        caret++; 
       } 
       else 
       { 
        if (caret == 1 && string.Empty + text[0] == NumberFormatInfo.CurrentInfo.NegativeSign) 
        { 
         text = NumberFormatInfo.CurrentInfo.NegativeSign + "0" + text.Substring(1); 
         caret++; 
        } 
       } 

       if (caret == text.Length) 
       { 
        selectionLength = 1; 
        textInserted = true; 
        text = text + NumberFormatInfo.CurrentInfo.NumberDecimalSeparator + "0"; 
        caret++; 
       } 
      } 
      else if (e.Text == NumberFormatInfo.CurrentInfo.NegativeSign) 
      { 
       textInserted = true; 
       if (Text.Contains(NumberFormatInfo.CurrentInfo.NegativeSign)) 
       { 
        text = text.Replace(NumberFormatInfo.CurrentInfo.NegativeSign, string.Empty); 
        if (caret != 0) 
         caret--; 
       } 
       else 
       { 
        text = NumberFormatInfo.CurrentInfo.NegativeSign + Text; 
        caret++; 
       } 
      } 

      if (!textInserted) 
      { 
       text = text.Substring(0, caret) + e.Text + 
        ((caret < Text.Length) ? text.Substring(caret) : string.Empty); 

       caret++; 
      } 

      try 
      { 
       double val = Convert.ToDouble(text); 
       double newVal = val;//ValidateLimits(GetMinimumValue(_this), GetMaximumValue(_this), val); 
       if (val != newVal) 
       { 
        text = newVal.ToString(); 
       } 
       else if (val == 0) 
       { 
        if (!text.Contains(NumberFormatInfo.CurrentInfo.NumberDecimalSeparator)) 
         text = "0"; 
       } 
      } 
      catch 
      { 
       text = "0"; 
      } 

      while (text.Length > 1 && text[0] == '0' && string.Empty + text[1] != NumberFormatInfo.CurrentInfo.NumberDecimalSeparator) 
      { 
       text = text.Substring(1); 
       if (caret > 0) 
        caret--; 
      } 

      while (text.Length > 2 && string.Empty + text[0] == NumberFormatInfo.CurrentInfo.NegativeSign && text[1] == '0' && string.Empty + text[2] != NumberFormatInfo.CurrentInfo.NumberDecimalSeparator) 
      { 
       text = NumberFormatInfo.CurrentInfo.NegativeSign + text.Substring(2); 
       if (caret > 1) 
        caret--; 
      } 

      if (caret > text.Length) 
       caret = text.Length; 

      Text = text; 
      CaretIndex = caret; 
      SelectionStart = caret; 
      SelectionLength = selectionLength; 
      e.Handled = true; 
     } 

     base.OnPreviewTextInput(e); 
    } 

    private static string ValidateValue(NumericType type, string value) 
    { 
     if (string.IsNullOrEmpty(value)) 
      return string.Empty; 

     value = value.Trim(); 
     switch (type) 
     { 
      case NumericType.Integer: 
       try 
       { 
        Convert.ToInt64(value); 
        return value; 
       } 
       catch 
       { 
       } 
       return string.Empty; 

      case NumericType.Decimal: 
       try 
       { 
        Convert.ToDouble(value); 
        return value; 
       } 
       catch 
       { 
       } 
       return string.Empty; 
     } 

     return value; 
    } 

    private static bool IsSymbolValid(NumericType type, string str) 
    { 
     switch (type) 
     { 
      case NumericType.Decimal: 
       if (str == NumberFormatInfo.CurrentInfo.NegativeSign || 
        str == NumberFormatInfo.CurrentInfo.NumberDecimalSeparator) 
        return true; 
       break; 

      case NumericType.Integer: 
       if (str == NumberFormatInfo.CurrentInfo.NegativeSign) 
        return true; 
       break; 

      case NumericType.Any: 
       return true; 
     } 

     if (type.Equals(NumericType.Integer) || type.Equals(NumericType.Decimal)) 
     { 
      foreach (char ch in str) 
      { 
       if (!Char.IsDigit(ch)) 
        return false; 
      } 

      return true; 
     } 

     return false; 
    } 

    protected override void OnGotFocus(RoutedEventArgs e) 
    { 
     base.OnGotFocus(e); 

     if (SelectAllOnGotFocus) 
      SelectAll(); 
    } 

    protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) 
    { 
     if (!IsKeyboardFocused && SelectAllOnGotFocus) 
     { 
      e.Handled = true; 
      Focus(); 
     } 

     base.OnPreviewMouseLeftButtonDown(e); 
    } 

正如你可以看到我從來沒有在這兩種控制的覆蓋或對MaxLength屬性的任何變化。然而,MaxLength與ReturnTextBox一起使用,並不適用於NumericTextBox。

謝謝你的幫助!

+0

顯示您的視圖模型屬性,其中BrRptAmt是如何定義你的MaxLength。 XAML是不夠的。 –

+0

您是通過代碼還是鍵盤輸入來填充NumericTextBox?您可以從代碼創建超過MaxLegnth的文本。該約束僅用於運行時擊鍵。 – drankin2112

+1

如果您發佈了您的NumericTextBox代碼,我會提供幫助。否則,我們只是猜測。 –

回答

1

e.Handled = !isValidif(isValid) { e.Handled = true }是你的問題。當你使用PreviewSomeEvent時,它們是隧道式的。這意味着他們從根源走向導致事件發生的源頭。在事件上設置Handled屬性意味着事件路由中的其他處理程序不會被引發。 MaxLength是在TextBox上定義的東西,或者至少比你的NumericTextBox更「原始」。

會發生什麼情況是,如果用戶輸入未通過驗證,該事件將不會被提升爲「深入隧道」以檢查長度:e.Handled = !isValid。如果它通過您的驗證,它不會被提出,因爲e.Handled = true

也許一個有用的類比可能是重寫一個方法並調用base或不。

欲瞭解更多有關事件的檢查here