键入时可以替换文本框中的字符吗?

时间:2013-09-24 00:43:28

标签: wpf input textbox

我们正在寻找一种方法,让文本框替换某些字符作为人物输入。注意,我们专注于控件本身,而不是绑定,视图模型等。为了这个问题,假设有一个窗口,文本框位于其中间,没有别的。没有数据,没有视图模型,没有绑定等等。

我已经更新了这个问题,因为看起来下面的所有答案都集中在绑定,依赖属性,coersion等等。虽然我很欣赏这些建议,但如上所述,我们的控制并不是一个受限制的控制,所以他们不是适用。

现在虽然我可以解释原因,但这会使这篇文章的篇幅延长五倍,因为它实际上是一个复杂而高级的用例,但这与问题本身无关,这就是为什么我这样做了简化了我们的场景,重点关注我们试图解决的具体问题,即关于文本框控件,或者可能是在您键入时替换字符的子类。

希望现在更有意义。

4 个答案:

答案 0 :(得分:17)

实现此目标的最佳方法是使用TextChanged事件:

    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);
            }
        }
    }

这有几个好处:

  • 你不是每次都经历整个字符串,只是更换的部分
  • 它在撤消管理器和粘贴文本方面表现良好
  • 您可以轻松地将其封装到附加属性中,该属性可以应用于任何文本框

答案 1 :(得分:3)

您可以使用IValueConverter。它涉及相当多的代码,但如果您想要转到MVVM路径,或者只是按照WPF的方式做事,那么它是首选方式。

首先,创建一个实现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;
    }
}

导入包含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">

在Window.Resources

中创建转换器的实例
<Window.Resources>
    <local:IllegalCharactersToUnderscoreConverter x:Key="IllegalCharactersToUnderscore" />
</Window.Resources>

在绑定表达式中使用转换器。 UpdateSourceTrigger = PropertyChanged是您键入时要转换的文本所必需的。

<TextBox Text="{Binding MyText, 
                Converter={StaticResource IllegalCharactersToUnderscore}, 
                UpdateSourceTrigger=PropertyChanged}"/>

答案 2 :(得分:2)

您可以将TextBox子类化,只需覆盖TextBox Text属性的元数据

即可
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;
    }
}

您根本不需要使用绑定,这只会在您键入时更新内部TextBox TextProperty

<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>

答案 3 :(得分:0)

我尝试通过在ViewModel属性中处理此问题来实现此功能,该属性绑定到TextBox本身就像下面一样,并且它可以正常工作。在这个例子中,我替换'!'用下划线。这里我只是将替换逻辑放在属性设置器中,如果有更改,我替换了文本并将属性更改为异步。

        private string text;
        public string Text
        {
            get { return text; }
            set
            {

                text = value;
                if (text.Contains("!"))
                {
                    text = text.Replace('!', '_');
                    Dispatcher.BeginInvoke((Action) (() => RaisePropertyChange("Text")));

                }
                RaisePropertyChange("Text");
            }
        }

并且文本框绑定是

<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"/>