Поведение WPF не работает должным образом

Я пытался создать поведение wpf. Что я делаю, это ищу нажатия клавиш OemPeriod,Decimal, backspace а также delete, Если строка в текстовом поле 101.55и пользователь нажимает Decimal или OemPeriod, перемещая курсор назад к 10, он удалит строку 1 после 10, и строка станет 10.55,

Эта часть работает как задумано. но настоящая проблема с back (backspace) а также Delete ключи.

Если текст в текстовом поле 10.55 и курсор находится после . (индекс каретки = 2) и пользователь нажимает клавишу Backspace, каретка сдвигает свою позицию на -1(перед десятичной дробью) и добавляет 55 после позиции каретки и текст становится 1055.00и то же самое происходит для Deleteключ.

текст отформатирован с использованиемStringFormat={}{0:#.00}

Вот мой код, может кто-нибудь сказать мне, что не так?

public class DecimalWatchingBehaviour : Behavior<UIElement> 
{

     protected override void OnAttached() 
     {
        base.OnAttached();
        TextBox t = AssociatedObject as TextBox;
        if (t != null) 
        {
            t.PreviewKeyUp += shiftCaretPosition;
        }
     }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        TextBox t = AssociatedObject as TextBox;
        if (t != null) 
        {
            t.PreviewKeyUp -= shiftCaretPosition;
        }
    }

    private void shiftCaretPosition(object sender, KeyEventArgs args) 
    {
        TextBox t = sender as TextBox;
        if (t == null) return;
        string txt = t.Text;
        if (!txt.Contains(".")) 
        {
            return;
        }
        int index = txt.IndexOf(".", StringComparison.Ordinal);
        int caretIndex = t.CaretIndex;
        if ((args.Key == Key.OemPeriod || args.Key == Key.Decimal)) 
        {
            t.Text = t.Text.Remove(t.CaretIndex, index);
            t.CaretIndex = t.Text.IndexOf(".", StringComparison.Ordinal) + 1;
        } else if (args.Key == Key.Back && txt.Substring(caretIndex < index ? caretIndex : index,
            caretIndex < index ? index - caretIndex : caretIndex - index) == ".") 
        {
            t.CaretIndex = index - 1;
        } else if (args.Key == Key.Delete && txt.Substring(caretIndex < index ? caretIndex : index,
            caretIndex < index ? index - caretIndex : caretIndex - index) == ".") 
        {
            t.CaretIndex = index + 1;
        }
    }
}

Вот объявление пространства имен xaml

xmlns:behaviour="clr-namespace:Utils.UI.Input.Behaviour;assembly=Utils"
<UserControl.Resources>        
        <behaviour:DecimalWatchingBehaviour x:Key="decimalWatchingBehaviour" />
</UserControl.Resources>

И текстовое поле в xaml

<TextBox
        Margin="5"
        Text="{Binding NewBatch.Cess,
               Mode=TwoWay,
               UpdateSourceTrigger=PropertyChanged,
               StringFormat={}{0:#.00}}" >
        <i:Interaction.Behaviors>
            <behaviour:DecimalWatchingBehaviour/>
        </i:Interaction.Behaviors>
</TextBox>

1 ответ

Решение

Вы можете обратиться к следующему простому фрагменту кода обработчика событий, который предоставляет аналогичные функциональные возможности, а именно: ограничение WPF TextBox1 ввод для числовой записи и некоторых специальных клавиш:

// PreviewKeyDown event proc: 
// only numeric and some special keys input allowed
TextBox1.PreviewKeyDown += (s, e) =>
{
    // intercept modifier "SHIFT" key
    if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
    { e.Handled = true; }

    // cast e.Key to int
    int _intKey = (int)e.Key;

    // allow the following key
    if (e.Key == Key.Back ||
        e.Key == Key.Delete ||
        e.Key == Key.Enter ||
        e.Key == Key.Return ||
        e.Key == Key.Tab ||
        e.Key == Key.OemPeriod ||
        e.Key == Key.OemComma ||
        e.Key == Key.Decimal ||
        e.Key == Key.Left ||
        e.Key == Key.Right ||
        (_intKey <= 43 && _intKey >= 34) ||
        (_intKey <= 84 && _intKey >= 73)) 
        {
              // the rest of the event handling code
              return;
        }
    else e.Handled = true;
};

где TextBox1 целевой элемент управления TextFox WPF Нет необходимости в дополнительном XAML или коде позади.

Надеюсь, что это может помочь.

Другие вопросы по тегам