2013-09-23 4 views
0

Я пытаюсь создать простой элемент управления вводами Hex. В этом элементе управления должен быть добавлен пробел после двух символов во время редактирования. Пользователь не должен принудительно нажимать клавишу пробела, место следует добавлять автоматически. Символы пробела тогда не должны быть привязаны. Также не должно быть фиксированной длины для шестнадцатеричной строки (например, это было бы с замаскированным текстовым полем).Автоматическое форматирование в WPF TextBox

Имеется ли расширение или контроль для этого или кто-либо уже создал такой элемент управления?

ответ

3

Простое решения будет делать это с помощью преобразователя:

public class SpaceConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     string newValue = ""; 
     int cnt = 0; 
     foreach (char c in value.ToString()) 
     { 
      if (cnt == 2) 
      { 
       newValue += " "; 
       cnt=0; 
      } 
      newValue += c; 
      cnt++; 
     } 
     return newValue; 
    } 

    public object ConvertBack(object value, Type targetTypes, object parameter, CultureInfo culture) 
    { 
     return value.Tostring().Replace(" ",""); 
    } 
} 

EDIT: Для того, чтобы установить курсор я создал вложенное свойство, которое заботится о форматировании:

public class TextBoxFormatter 
{ 
    public static readonly DependencyProperty EnableFormattingProperty = 
     DependencyProperty.RegisterAttached("EnableFormatting", typeof(bool), typeof(TextBoxFormatter), 
      new PropertyMetadata(default(bool), PropertyChangedCallback)); 

    private static void PropertyChangedCallback(DependencyObject dependencyObject, 
     DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) 
    { 
     TextBox tb = dependencyObject as TextBox; 
     if (tb != null) 
     { 
      bool value = (bool)dependencyPropertyChangedEventArgs.NewValue; 
      tb.TextChanged -= TBTextChanged; 
      if (value) 
      { 
       Format(tb, true); 
       tb.TextChanged += TBTextChanged; 
      } 
     } 
    } 

    public static void SetEnableFormatting(TextBox element, bool value) 
    { 
     element.SetValue(EnableFormattingProperty, value); 
    } 

    public static bool GetEnableFormatting(TextBox element) 
    { 
     return (bool) element.GetValue(EnableFormattingProperty); 
    } 

    private static void TBTextChanged(object sender, TextChangedEventArgs e) 
    { 
     Format(sender as TextBox); 
    } 

    private static void Format(TextBox tb, bool init = false) 
    { 
     if (tb != null) 
     { 
      int ci = tb.CaretIndex; 
      string newValue = ""; 
      int cnt = 0; 
      foreach (char c in tb.Text) 
      { 
       if (c != ' ') 
       { 
        if (cnt > 0 && ShouldFormat(cnt)) 
        { 
         newValue += " "; 
         if (ci > cnt && init) 
          ci++; 
        } 
        cnt++; 
        newValue += c; 
       } 
      } 
      tb.Text = newValue; 
      SetCaret(tb, ci); 
     } 
    } 

    private static void SetCaret(TextBox tb, int oldCaret) 
    { 
     if (oldCaret <= 0 || oldCaret >= tb.Text.Length) 
      return; 

     if (tb.Text[oldCaret-1] != ' ' && tb.Text[oldCaret] != ' ') 
      tb.CaretIndex += oldCaret; 
     else 
      tb.CaretIndex = oldCaret+1; 
    } 

    private static bool ShouldFormat(int index) 
    { 
     return index%2 == 0; 
    } 
} 

Как использовать:

<TextBox ns:TextBoxFormatter.EnableFormatting="True"></TextBox> 
+0

Хорошая идея, но она не соответствует критериям «.. пока пользователь редактирует». Конвертер вызывается только тогда, когда пользователь покидает текстовое поле. –

+0

@ RolandBär Нет, если вы установите свойство UpdateSourceTrigger = PropertyChanged в вашей привязке он обновляет значение сразу, когда пользователь набирает. –

+0

Да, это работает, но возникает еще одна проблема: при вводе третьего символа пробел вставляется, но курсор остается в позиции. Поэтому ввод 1-2-3-4 приводит к " 12 43 ", возникающие для каждого вставленного пространства ... Любая идея, как это решить? –

0

Вы можете реализовать свое собственный элемент управления, который делает это, переопределив это OnTextChanged метод

public class HexTextBox : TextBox 
{ 
    private bool isUserTextChaned = true; 

    protected override void OnTextChanged(TextChangedEventArgs e) 
    { 
     if (isUserTextChaned) 
     { 
      isUserTextChaned = false; 

      string temp = Text.Replace(" ", string.Empty); 

      // Support for backspace 
      if (e.Changes.First().RemovedLength > 0 && !Text.EndsWith(" ")) 
      { 
       temp = temp.Substring(0, temp.Length - e.Changes.First().RemovedLength); 
      } 

      // Insert spaces 
      temp = Regex.Replace(temp, @"(.{2})", "$1 "); 

      // Update text 
      Text = temp; 

      isUserTextChaned = true; 

      // Set cursor 
      Select(Text.Length, Text.Length); 

      base.OnTextChanged(e); 
     } 
    } 
} 

Explaination:

Поскольку каждое изменение Text собственности запустит TextChanged события, чтобы избежать рекурсий я ve добавили поле isUserTextChanged, чтобы определить, что TextChanged был произведен извне.

Далее, каждый третий символ мы переопределяем свойство Text с '' между двумя символами.

Наконец, мы устанавливаем курсор в конец Text, выбирая последний символ Select(Text.Length, Text.Length);.

Надеется, что это помогает :)

+0

Можете ли вы помочь мне, как манипулировать текстом, чтобы получить полезный элемент управления? Просто добавление пробела ('Text + =" ";') перемещает курсор в начало строки, поэтому ввод 1-2-3-4 приводит к «4312___» (где _ означает пробел). –

+0

@ RolandBär Вы пробовали 'Text =" "+ Text;'? –

+0

Это разрешает проблему пробелов, появляющихся в конце, но не проблему, с которой курсор перемещается в начало TextBox, поэтому результат ввода 1-2-3-4 равен «_34_12», но это должно быть «12_34_» ». –

Смежные вопросы