What is the best way to create a WPF TextBox that replaces spaces with underscores?

I am creating FilteredTextBoxin WPF that subclasses the included control TextBox. FilteredTextBoxshould allow for characters in a range [a-zA-Z0-9_], and I have this part that works pretty much. I hooked in OnPreviewTextInputto handle typed characters, OnPreviewDropto filter out wrapped and discarded characters, and I added a PreviewExecutedHandler that runs whenever the command controls insert processing.

So far so good.

The tricky part is that the control also needs to replace spaces with underscores as you type.

I came up with a solution, but it feels pretty hacky, and I don't know what it is missing. I feel that there must be a better technique that I simply don’t know about. What I've done:

internal class FilteredTextBox : TextBox
{
    public FilteredTextBox()
    {
        CommandManager.AddPreviewExecutedHandler(this, this.HandlePreviewExecuteHandler);
    }

    private void HandlePreviewExecuteHandler(object sender, ExecutedRoutedEventArgs e)
    {
        var uiCmd = e.Command as RoutedUICommand;
        if (uiCmd != null && (uiCmd.Text == "Space" || uiCmd.Text == "ShiftSpace"))
        {
            // We're manually handling spaces, so we need to make appropriate checks.
            if (this.Text.Length == this.MaxLength) return;

            if (this.SelectionLength == 0)
            {
                // If the user is just typing a space normally
                // We need to cache CaretIndex b/c it reset to 0 when we set Text.
                var tmpIndex = this.CaretIndex;
                this.Text = this.Text.Insert(tmpIndex, "_");
                this.CaretIndex = tmpIndex + 1;
            }
            else
            {
                // Otherwise, replace the selected text with the underscore and fixup the caret.
                this.SelectedText = "_";
                this.CaretIndex += this.SelectedText.Length;
                this.SelectionLength = 0;
            }

            e.Handled = true; // If someone hits the spacebar, say we handled it.
            return;
        }
    }
}

Is there a smarter way?

+3
source share
3 answers

I think your logic is good, but I would put it on redefinition OnPreviewKeyDown.

+3
source

I would snap TextBoxto ValueConverter, which removes spaces on demand and replaces them with underscores.

ValueConverter will look something like this:

public class SpaceConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return System.Convert.ToString(value); 
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            string text = System.Convert.ToString(value);

            //the meat and potatoes is this line
            text = text.Replace(" ", "_");    

            return text;
        }
    }

And yours TextBoxwill be attached to it as follows:

<TextBox Text="{Binding Path=UserString, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource SpaceConverter}}" />

Note what UserStringshould be in the current DataContext.

SpaceConverter XAML. , , UserControl, :

<UserControl.Resources>
   <local:SpaceConverter x:Key="SpaceConverter" />
</UserControl.Resources>

local , SpaceConverter.cs.

+4

Would it be better to simply replace the _ space when the control loses focus, or do you absolutely need to replace it when the user entered it?

+1
source

Source: https://habr.com/ru/post/1768235/


All Articles