WPF TextBox中的自动格式化

时间:2013-09-23 09:18:29

标签: .net wpf textbox

我尝试创建一个简单的Hex输入控件。在此控件中,在用户编辑时,应在2个字符之后添加空格字符。不应强迫用户按空格键,应自动添加空格。 那么空间字符不应该是绑定值。十六进制字符串也不应该有固定长度(就像使用蒙版文本框一样)。

是否有可用的扩展或控件,或者是否有人已经创建了这样的控件?

2 个答案:

答案 0 :(得分: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(" ","");
    }
}

编辑:要设置光标我创建了一个附加属性,它负责格式化:

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>

答案 1 :(得分: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);
        }
    }
}

阐释:

由于对Text属性的每次更改都会触发TextChanged事件,为了避免递归,我添加了isUserTextChanged字段以确定TextChanged是从外部触发的

接下来,我们每隔三个字符重新定义Text属性,每两个字符之间有一个''。

最后,我们通过选择最后一个字符Text将光标设置为Select(Text.Length, Text.Length);的末尾。

希望这会有所帮助:)