【发布时间】:2014-01-16 23:34:58
【问题描述】:
对于我的 WPF 应用程序,我创建了几个基于 TextBox 的自定义控件。其中包括 NumericTextBox、WatermarkTextBox 和 ReturnTextBox。
Numeric 和 Watermark 继承自 ReturnTextBox,ReturnTextBox 继承自 TextBox。
当我使用我的任何自定义文本框时,它们的效果都很好。一个问题似乎是 NumericTextBox 和 MaxLength 属性。该属性现在被忽略并且不起作用。我的任何自定义控件中都没有代码覆盖或弄乱 MaxLength 属性。
当我在 ReturnTextBox 上使用 MaxLength 时,它的工作原理与您预期的一样:
<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);
}
}
数字文本框
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 一起使用。
感谢您的帮助!
【问题讨论】:
-
显示 BrRptAmt 所在的 ViewModel 属性以及如何定义 MaxLength。 XAML 还不够。
-
您是通过代码还是键盘输入来填充 NumericTextBox?您可以从代码中创建比 MaxLegnth 更长的文本。该约束仅用于运行时击键。
-
如果您发布 NumericTextBox 代码,我会提供帮助。否则,我们只是猜测。
-
已添加代码。 @drankin2112 我正在使用键盘输入填充 NumericTextBox,我只想使用 MaxLength 作为用户输入验证的另一层。
-
@lll Viewmodel 属性我也在绑定:
public Int64? BrRptAmt { get { return brRptAmt; } set { if (brRptAmt != value) { brRptAmt = value; RaiseChanged(() => this.BrRptAmt); } } }
标签: c# .net wpf inheritance custom-controls