Okay, there is a simple way that you can "fake" this relatively easy but depending on the width of the alternate characters and how they map into the width of the current characters, there may be a bit of a jarring interface. The trick is to overlay two TextBoxes over each other. The top one accepts the input but is, effectively, invisible. The one underneath is the one that displays your actual content. The XAML looks a bit like this:
<Grid>
<TextBox Text="{Binding ConvertedText}" />
<TextBox Foreground="Transparent" Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" Background="Transparent" />
</Grid>
Now, the ViewModel behind this couldn't be simpler. Effectively, when you change the Text property, it automatically triggers the conversion code.
public string Text
{
get => _text;
set
{
if (_text != value)
{
_text = value;
ConvertedText = _text.Replace("1", "y");
OnPropertyChanged();
}
}
}
public string ConvertedText
{
get => _convertedText;
set
{
if (_convertedText != value)
{
_convertedText = value;
OnPropertyChanged();
}
}
}
And that's it, a potentially simple solution to your problem.