我尝试创建一个简单的十六进制输入控件。在这个控件中,当用户编辑时,应该在 2 个字符之后添加一个空格字符。不应强迫用户按空格键,应自动添加空格。空格字符不应该在绑定值中。十六进制字符串也不应该有固定的长度(就像带有掩码的文本框一样)。
是否有可用的扩展或控件,或者是否有人已经创建了这样的控件?
一个简单的解决方案是使用转换器执行此操作:
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>
您可以通过覆盖它的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
通过选择最后一个 char将光标设置到末尾Select(Text.Length, Text.Length);
。
希望这可以帮助 :)