我们正在寻找一种方法,让文本框替换某些字符作为人物输入。注意,我们专注于控件本身,而不是绑定,视图模型等。为了这个问题,假设有一个窗口,文本框位于其中间,没有别的。没有数据,没有视图模型,没有绑定等等。
我已经更新了这个问题,因为看起来下面的所有答案都集中在绑定,依赖属性,coersion等等。虽然我很欣赏这些建议,但如上所述,我们的控制并不是一个受限制的控制,所以他们不是适用。
现在虽然我可以解释原因,但这会使这篇文章的篇幅延长五倍,因为它实际上是一个复杂而高级的用例,但这与问题本身无关,这就是为什么我这样做了简化了我们的场景,重点关注我们试图解决的具体问题,即关于文本框控件,或者可能是在您键入时替换字符的子类。
希望现在更有意义。
答案 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}"/>