如何在WPF TextBox中指定字母间距或字距?

时间:2011-04-30 17:47:52

标签: wpf xaml textbox kerning

我想修改WPF TextBox中字符之间的间距 类似于CSS中可用的letter-spacing: 5px事物 我认为在XAML中是可能的;什么是最简单的方法?

我找到了“Introduction to the GlyphRun Object and Glyphs Element”文件,发现它非常无益。

这是该页面的代码示例:

<!-- "Hello World!" with explicit character widths for proportional font -->
<Glyphs 
   FontUri             = "C:\WINDOWS\Fonts\ARIAL.TTF"
   FontRenderingEmSize = "36"
   UnicodeString       = "Hello World!"
   Indices             = ",80;,80;,80;,80;,80;,80;,80;,80;,80;,80;,80"
   Fill                = "Maroon"
   OriginX             = "50"
   OriginY             = "225"
/>

相同的文档页面为Indices属性的作用提供了“解释”:

enter image description here

我不知道这意味着什么。我也不确定指数是否正确 - 代码中的注释说的是“字符宽度”,我并不关心。我想在字符之间调整的宽度。

此外,没有关于如何将Glyphs元素应用于TextBox的示例。当我尝试它时,我的WPF测试应用程序崩溃了。


我想要做的是略微增加WPF TextBox中绘制字符之间出现的空白区域。案文的长度和内容各不相同。每次有新角色时我是否必须修改Indicies属性?有没有办法说“为每个角色增加20%的空间”。

任何人都可以帮助我吗?

4 个答案:

答案 0 :(得分:17)

我尝试了Glyphs和FontStretch,并且无法轻易获得我想要的结果。我能够提出一种适用于我的目的的方法。也许它也适用于其他人。

<ItemsControl ItemsSource="{Binding SomeString}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}" 
                       Margin="0,0,5,0"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

我可以绑定到任何字符串,不需要进行任何字符宽度检测来正确设置间距。右边距是字母之间的空格

示例:

Kerning

答案 1 :(得分:1)

FontStretch是你的选择吗?

否则你可能想查看this有一个图像,显示提前宽度的含义。虽然我之前没有这样做过,也不知道这是否有效,左右侧轴承可能是你想要的!

答案 2 :(得分:1)

我找到了一种使用 TextBlock 类设置字母间距的方法,因为它支持 TranslateTransforms。通过用自定义的 PropertyChangedCallback 替换默认的 TextBlock.TextProperty,我们可以将 TranslateTransform 应用于 TextBlock 中的每个字母。

这是我完成的完整分步编码:

首先,我们创建一个自定义类并从 TextBlock 继承,如下所示:

using System.Windows.Controls;

namespace MyApp
{
    class SpacedLetterTextBlock : TextBlock
    {
        public SpacedLetterTextBlock() : base()
        {
        }
    }
}

然后,在 XAML 中,我们将 TextBlock 更改为我们的自定义类(更多信息可以在 here 中找到):

<Window x:Class="MyApp.MainWindow"
        ...
        xmlns:app="clr-namespace:MyApp">
   <Grid>
       <app:SpacedLetterTextBlock>
           Some Text
       </app:SpacedLetterTextBlock>
   </Grid>
</Window>

最后,在 InitializeComponent() 代码隐藏文件中的 .cs 方法之前,像这样添加 OverrideMetadata 方法:

// This line of code adds our own callback method to handle any changes in the Text
//   property of the TextBlock
SpacedLetterTextBlock.TextProperty.OverrideMetadata(
    typeof(SpacedLetterTextBlock),
    new FrameworkPropertyMetadata(null,
            FrameworkPropertyMetadataOptions.AffectsRender,
            new PropertyChangedCallback(OnTextChanged)
    )
);

...并在每次 TranslateTransform 更改时将 TextProperty 应用于每个字母:

private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    SpaceLettersOut(d);
}

// This method takes our custom text block and 'moves' each letter left or right by 
//  applying a TranslateTransform
private static void SpaceLettersOut(DependencyObject d)
{
    SpacedLetterTextBlock thisBlock = (SpacedLetterTextBlock)d;
            
    for (int i = 1; i <= thisBlock.Text.Length; i++)
    {
        // TranslateTransform supports doubles and negative numbers, so you can have
        //  whatever spacing you need - do see 'Notes' section in the answer for
        //  some limitations.
        TranslateTransform transform = new TranslateTransform(2, 0);
        TextEffect effect = new TextEffect();
        effect.Transform = transform;
        effect.PositionStart = i;
        effect.PositionCount = thisBlock.Text.Length;

        thisBlock.TextEffects.Add(effect);
        if (effect.CanFreeze)
        {
            effect.Freeze();
        }
    }
}

注意事项

首先,我是 WPF 和 C# 的完全新手,所以我的答案可能不是可用的最干净的解决方案。如果您对如何改进此答案有任何意见,我们将不胜感激!

其次,我还没有用大量 TextBlock 元素测试过这个解决方案,并且(可能)会造成巨大的性能损失,因为 TranslateTransform 应用于 {{ 1}}。

最后,TextBlock.Text 的文本超出了 TextBlock 的任何正 X 值的范围。我认为您可以重新计算 TranslateTransform 的宽度,然后才以编程方式放置它 (?)

答案 3 :(得分:-1)

它的价值。 。

如果您可以选择将实现切换到RichTextBox,这可能比您在2013年9月找到的解决方案更容易。我只是根据自己的需要尝试它,它可以满足我的需要。我没有看到使用RichTextBox来控制像排版者这样的单个空格的字距调整。但TextBox正在占用额外的空间(将多个相邻空间合并到一个空间),就像HTML一样。我需要空格显示与文本字符串相同的间距,RichTextBox就是这样做的。

<RichTextBox x:Name="MyRichTextBox"></RichTextBox>

我不是专家,但似乎您无法在XAML中指定文字内容。我必须在代码隐藏事件中指定它:

this.MyRichTextBox.AppendText("V A R I E D      S P A C E S");