11

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

我已经更新了这个问题,因为下面的所有答案似乎都集中在绑定、依赖属性、强制等。虽然我很欣赏这些建议,正如我上面所说的,但我们的控件不是绑定控件,因此它们不适用。

现在虽然我可以解释其中的原因,但这会使这篇文章长五倍,因为它实际上是一个复杂而高级的用例,但这与问题本身无关,这就是我简化我们的场景的原因专注于我们正在尝试解决的特定问题,这是关于文本框控件,或者可能是您键入时替换字符的子类。

希望现在更有意义。

4

4 回答 4

19

完成此操作的最佳方法是使用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);
            }
        }
    }

这有几个优点:

  • 你不会每次都遍历整个字符串,只是替换的部分
  • 它与撤消管理器和粘贴文本表现良好
  • 您可以轻松地将其封装到可应用于任何文本框的附加属性中
于 2013-09-24T06:24:10.947 回答
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}"/>
于 2013-09-24T02:30:54.470 回答
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>
于 2013-09-24T01:10:08.307 回答
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}"/>
于 2013-09-24T03:30:23.210 回答