Reputation: 1740
I try to create a simple Hex Input Control. In this control there should be a space char be added after 2 chars while the user is editing. The user should not be forced to press the space bar, the space should be added automatically. The space chars should then not be in the binded value. There also should not be a fixed length for the hex string (like it would be with a masked textbox).
Is there an extension or control available for this or has anybody already created such a control?
Upvotes: 0
Views: 700
Reputation: 6547
You can implement your own control that does this, by overriding it's OnTextChanged
method
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:
Since every change to the Text
property will fire the TextChanged
event, to avoid recursion I've added the isUserTextChanged
field to determine that the TextChanged
was fired externally.
Next, every third character we redefine the Text
property with a ' ' inbetween every two chars.
Finally, we set the cursor to the end of the Text
by selecting the last char Select(Text.Length, Text.Length);
.
Hope this helps :)
Upvotes: 1
Reputation: 6014
An easy solution would be doing this with a converter:
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: To set the cursor I created a attached property which takes care about the formatting:
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;
}
}
How to use it:
<TextBox ns:TextBoxFormatter.EnableFormatting="True"></TextBox>
Upvotes: 3