WPF文本框值不包括十进制数字0

时间:2011-05-17 14:47:58

标签: wpf textbox decimal mask

在WPF文本框的KeyUp事件中,textBox.Text的值是正确的,除非用户输入0.例如,如果用户输入5.88,则textBox.Text值为“5.88”。如果用户输入5.80,则textBox.Text值为“5.8”(0被删除)。我们只允许用户输入一个十进制数字,因此,如果它们输入5.80,我们要修剪0.问题是我们不能,因为修剪的代码只能看到“5.8”。操作完成后,文本框中仍会显示“5.80”,供用户查看。

知道为什么会这样吗?

注意:文本框中应用了转换器,但KeyUp事件将值设置为textBox.Text。因此,如果转换器产生5.8,则textBox.Text值将设置为“5.8”。

编辑:以下是一些代码:

<Window.Resources>
    <converters:StringToBooleanConverter x:Key="stringToBooleanConverter" />
    <converters:SecondsToMinutesConverter x:Key="secondsToMinutesConverter" />
</Window.Resources>

<TextBox Text="{Binding ApplyTimeInSeconds, Converter={StaticResource secondsToMinutesConverter},
TargetNullValue={x:Static sys:String.Empty}, UpdateSourceTrigger=PropertyChanged,
NotifyOnValidationError=True, ValidatesOnExceptions=True}"                                                         
vab:Validate.BindingForProperty="Text"
Name="ApplyTimeTextBox"
KeyUp="ApplyTimeTextBox_KeyUp"
Width="75" VerticalAlignment="Center" Style="{StaticResource textBoxInError}"
IsEnabled="{Binding ElementName=applyTimeCheckbox, Path=IsChecked}"/>



private void ApplyTimeTextBox_KeyUp(object sender, KeyEventArgs e)
    {
        ViewUtility.RemoveExtraDecimalDigits(sender as TextBox, 1);
    }

    // We don't want to allow more than one decimal position. So, if the user types 4.38, remove the 8. Or change 4.389 to 4.3.
    internal static void RemoveExtraDecimalDigits(TextBox textBox, int numberOfDecimalDigitsAllowed)
    {
        if (!textBox.Text.Contains(".")) { return; }

        string originalText = textBox.Text;

        textBox.Text = GetValueWithCorrectPrecision(textBox.Text, numberOfDecimalDigitsAllowed);

        // If the text changed, move the cursor to the end. If there was no change to make, or maybe the user hit the
        // HOME key, no reason to move the cursor.
        if (textBox.Text != originalText)
        {
            MoveCursorToEnd(textBox);
        }
    }

    private static string GetValueWithCorrectPrecision(string textValue, int numberOfDecimalDigitsAllowed)
    {
        int indexOfDecimalPoint = textValue.IndexOf('.');

        string[] numberSection = textValue.Split('.');

        if (numberSection[1].Length > numberOfDecimalDigitsAllowed)
        {
            // Keep the decimal point and the desired number of decimal digits (precision)
            return textValue.Remove(indexOfDecimalPoint + numberOfDecimalDigitsAllowed + 1);
        }

        return textValue;
    }

    private static void MoveCursorToEnd(TextBox textBox)
    {
        textBox.Select(textBox.Text.Length, 0);  // Keep cursor at end of text box
    }

这是转换器:

public class SecondsToMinutesConverter : IValueConverter
{
    #region IValueConverter Members

    /// <summary>
    /// Converts a value from the source (domain object/view model) to the target (WPF control).
    /// </summary>
    /// <param name="value">The value produced by the binding source.</param>
    /// <param name="targetType">The type of the binding target property.</param>
    /// <param name="parameter">The converter parameter to use.</param>
    /// <param name="culture">The culture to use in the converter.</param>
    /// <returns>
    /// A converted value. If the method returns null, the valid null value is used.
    /// </returns>
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if(value == null) { return null; }

        decimal bindingSourceValueAsDecimal = System.Convert.ToDecimal(value, CultureInfo.CurrentCulture);

        return Decimal.Round(bindingSourceValueAsDecimal / 60, 2);
    }

    /// <summary>
    /// Converts a value from the target (WPF control) to the source (domain object/view model).
    /// </summary>
    /// <param name="value">The value that is produced by the binding target.</param>
    /// <param name="targetType">The type to convert to.</param>
    /// <param name="parameter">The converter parameter to use.</param>
    /// <param name="culture">The culture to use in the converter.</param>
    /// <returns>
    /// A converted value. If the method returns null, the valid null value is used.
    /// </returns>
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if(value == null) { return null; }

        decimal bindingTargetValueAsDecimal;

        if(Decimal.TryParse(value.ToString(), out bindingTargetValueAsDecimal) == false) { return DependencyProperty.UnsetValue; }

        return Math.Round(bindingTargetValueAsDecimal * 60, 2);
    }

    #endregion
}

2 个答案:

答案 0 :(得分:0)

实际上,我试图重现行为,没有转换器(因为我不知道它是如何约束的),如果我很好地预期行为,它运作良好......

当我输入5.88时,最后一个数字被删除(我得到5.8)。 当我输入5.80时,最后一个数字也被删除(我得到5.8)。

你可以更具体地说明你不能做什么吗? 你试过没有任何转换器吗?或者您可以使用转换器使用XAML更新代码吗?

答案 1 :(得分:0)

建议您使用PreviewKeyUp或PreviewTextInput而不是KeyUp事件。

作为替代方案,您可能希望屏蔽文本框,或者 1.使用MaskedTextBox,或
2. modifying the behaviour of textbox使用附加财产。

如果是2,您可能需要根据需要修改ValidateValue函数。