简体   繁体   中英

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

I'm creating a FilteredTextBox in WPF that subclasses the included TextBox control. The FilteredTextBox must only allow characters in the range [a-zA-Z0-9_] to be entered, and I've got that part pretty much working. I've hooked into OnPreviewTextInput to handle typed characters, OnPreviewDrop to filter characters that are dragged and dropped, and I've added a PreviewExecutedHandler that runs whenever a command is executed on the control to handle pasting.

So far, so good.

The tricky part is that the control should also replace spaces with underscores when they're typed in.

I've come up with a solution, but it feels pretty hacked together and I don't know what it's missing. I feel like there's got to be a better technique that I'm just not aware of. 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's 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?

I would bind the TextBox to a ValueConverter that eliminates whitespace on demand and replaces them with underscores.

The ValueConverter would 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 your TextBox would bind to it this way:

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

Note that UserString would have to be in the current DataContext .

Don't forget to define SpaceConverter in the XAML as well. One way to do this, assuming you're working on a UserControl , would be:

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

Where local is defined as the namespace containing SpaceConverter.cs.

我认为你的逻辑很好,但是我把它放在OnPreviewKeyDown的覆盖中。

当控件失去焦点时,用_替换空格是否更好?或者当用户将其键入时,您是否绝对需要更换空间?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM