Can you replace characters in a textbox as you type?
The best way to accomplish this is using the TextChanged
event:
private void OnTextChanged(object sender, TextChangedEventArgs e) { var tb = (TextBox)sender; using (tb.DeclareChangeBlock()) { foreach (var c in e.Changes) { if (c.AddedLength == 0) continue; tb.Select(c.Offset, c.AddedLength); if (tb.SelectedText.Contains(' ')) { tb.SelectedText = tb.SelectedText.Replace(' ', '_'); } tb.Select(c.Offset + c.AddedLength, 0); } } }
This has several advantages:
- You don't go through the entire string every time, just the replaced part
- It behaves well with the undo manager and with pasting text
- You can easily encapsulate it into an attached property which can be applied to any text box
You can use an IValueConverter. It involves quite a bit of code, but it's the preferred way if you ever want to go the MVVM path, or just do things the WPF way.
First, create a class that implements IValueConverter
public class IllegalCharactersToUnderscoreConverter : IValueConverter{ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { var stringValue = value as String; if(stringValue == null) return value; return RemoveIllegalCharacters(stringValue); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return value; }}
Import the namespace containing your ValueConverter
<Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="MainWindow" Height="350" Width="525">
Create an instance of your converter in Window.Resources
<Window.Resources> <local:IllegalCharactersToUnderscoreConverter x:Key="IllegalCharactersToUnderscore" /></Window.Resources>
Use the converter in your binding expression. UpdateSourceTrigger=PropertyChanged is required for the text to be converted as you type.
<TextBox Text="{Binding MyText, Converter={StaticResource IllegalCharactersToUnderscore}, UpdateSourceTrigger=PropertyChanged}"/>
You could subclass TextBox you can just override the Metadata of the TextBox Text property
public class FilteredTextBox : TextBox{ public FilteredTextBox() { TextBox.TextProperty.OverrideMetadata(typeof(FilteredTextBox), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, null, CoerceMyTextValue, true, UpdateSourceTrigger.PropertyChanged)); } private static object CoerceMyTextValue(DependencyObject d, object baseValue) { if (baseValue != null) { var userEnteredString = baseValue.ToString(); return userEnteredString.Replace(' ', '_'); } return baseValue; }}
And you dont need to use bindings at all, this will just update the internal TextBox TextProperty as you type
<Window x:Class="WpfApplication13.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="428" Width="738" Name="UI" xmlns:my="clr-namespace:WpfApplication13" > <StackPanel> <my:FilteredTextBox /> </StackPanel></Window>