4

我正在使用 FormattedText 类创建文本 - 但是在使用此类时如何下标或上标文本?我找到了使用 TextBlock 时如何执行此操作的解决方案,但我使用的是 FormattedText 而不是 TextBlock ):感谢您的任何提示!

4

2 回答 2

11

FormattedText不能做下标/上标 - 但TextFormatter可以。

TextFormatter是一个低级 API,您需要编写大量代码才能使用它 - 但大多数代码只是将所有用于传递格式参数的类的子类化 int TextFormatter

如何使用文本格式化程序

TextFormatter接受一个TextSource对象并生成多个TextLine对象(每条线一个),TextLine.Draw然后可以使用该方法将线绘制到绘图上下文中。

该类TextSource是抽象的,您必须对其进行子类化并覆盖GetTextRun仅返回TextRun位于提供的字符位置的对象的方法。

TextRun也是抽象的 - 但它确实有您可以使用的子类 - 有趣的类是TextCharacters包含字符串和格式信息。

格式化信息在一个TextRunProperties对象中,不幸的是,这是另一个你必须继承的抽象类。

TextRunProperties有一个TypographyProperties类型的属性TextRunTypographyProperties

TextRunTypographyProperties是另一个需要子类化的抽象类。

最后TextRunTypographyProperties具有Variants您可以使用的属性,例如 TextBlock 示例。

代码示例

这是我可以编写的用于绘制上标文本的最少代码:

首先,我们的 TextRunProperties 和 TextRunTypographyProperties 可以返回上标字体变体:

class CustomTextRunProperties : TextRunProperties
{
    private bool _superscript;
    public CustomTextRunProperties(bool superscript)
    {
        _superscript = superscript;
    }
    public override System.Windows.Media.Brush BackgroundBrush
    {
        get { return null; }
    }

    public override CultureInfo CultureInfo
    {
        get { return CultureInfo.CurrentCulture; }
    }

    public override double FontHintingEmSize
    {
        get { return 22; }
    }

    public override double FontRenderingEmSize
    {
        get { return 22; }
    }

    public override Brush ForegroundBrush
    {
        get { return Brushes.Black; }
    }

    public override System.Windows.TextDecorationCollection TextDecorations
    {
        get { return new System.Windows.TextDecorationCollection(); }
    }

    public override System.Windows.Media.TextEffectCollection TextEffects
    {
        get { return new TextEffectCollection(); }
    }

    public override System.Windows.Media.Typeface Typeface
    {
        get { return new Typeface("Calibri"); }
    }

    public override TextRunTypographyProperties TypographyProperties
    {
        get
        {
            return new CustomTextRunTypographyProperties(_superscript);
        }
    }

}

class CustomTextRunTypographyProperties : TextRunTypographyProperties
{
    private bool _superscript;

    public CustomTextRunTypographyProperties(bool superscript)
    {
        _superscript = superscript;
    }

    public override int AnnotationAlternates
    {
        get { return 0; }
    }

    public override bool CapitalSpacing
    {
        get { return false; }
    }

    public override System.Windows.FontCapitals Capitals
    {
        get { return FontCapitals.Normal; }
    }

    public override bool CaseSensitiveForms
    {
        get { return false; }
    }

    public override bool ContextualAlternates
    {
        get { return false; }
    }

    public override bool ContextualLigatures
    {
        get { return false; }
    }

    public override int ContextualSwashes
    {
        get { return 0; }
    }

    public override bool DiscretionaryLigatures
    {
        get { return false; }
    }

    public override bool EastAsianExpertForms
    {
        get { return false; }
    }

    public override System.Windows.FontEastAsianLanguage EastAsianLanguage
    {
        get { return FontEastAsianLanguage.Normal; }
    }

    public override System.Windows.FontEastAsianWidths EastAsianWidths
    {
        get { return FontEastAsianWidths.Normal; }
    }

    public override System.Windows.FontFraction Fraction
    {
        get { return FontFraction.Normal; }
    }

    public override bool HistoricalForms
    {
        get { return false; }
    }

    public override bool HistoricalLigatures
    {
        get { return false; }
    }

    public override bool Kerning
    {
        get { return true; }
    }

    public override bool MathematicalGreek
    {
        get { return false; }
    }

    public override System.Windows.FontNumeralAlignment NumeralAlignment
    {
        get { return FontNumeralAlignment.Normal; }
    }

    public override System.Windows.FontNumeralStyle NumeralStyle
    {
        get { return FontNumeralStyle.Normal; }
    }

    public override bool SlashedZero
    {
        get { return false; }
    }

    public override bool StandardLigatures
    {
        get { return false; }
    }

    public override int StandardSwashes
    {
        get { return 0; }
    }

    public override int StylisticAlternates
    {
        get { return 0; }
    }

    public override bool StylisticSet1
    {
        get { return false; }
    }

    public override bool StylisticSet10
    {
        get { return false; }
    }

    public override bool StylisticSet11
    {
        get { return false; }
    }

    public override bool StylisticSet12
    {
        get { return false; }
    }

    public override bool StylisticSet13
    {
        get { return false; }
    }

    public override bool StylisticSet14
    {
        get { return false; }
    }

    public override bool StylisticSet15
    {
        get { return false; }
    }

    public override bool StylisticSet16
    {
        get { return false; }
    }

    public override bool StylisticSet17
    {
        get { return false; }
    }

    public override bool StylisticSet18
    {
        get { return false; }
    }

    public override bool StylisticSet19
    {
        get { return false; }
    }

    public override bool StylisticSet2
    {
        get { return false; }
    }

    public override bool StylisticSet20
    {
        get { return false; }
    }

    public override bool StylisticSet3
    {
        get { return false; }
    }

    public override bool StylisticSet4
    {
        get { return false; }
    }

    public override bool StylisticSet5
    {
        get { return false; }
    }

    public override bool StylisticSet6
    {
        get { return false; }
    }

    public override bool StylisticSet7
    {
        get { return false; }
    }

    public override bool StylisticSet8
    {
        get { return false; }
    }

    public override bool StylisticSet9
    {
        get { return false; }
    }

    public override FontVariants Variants
    {
        get { return _superscript ? FontVariants.Superscript: FontVariants.Normal; }
    }
}

还有一个类似的段落格式类(取自 MSDN TextFormatter 示例):

class GenericTextParagraphProperties : TextParagraphProperties
{
    public GenericTextParagraphProperties(
       FlowDirection flowDirection,
       TextAlignment textAlignment,
       bool firstLineInParagraph,
       bool alwaysCollapsible,
       TextRunProperties defaultTextRunProperties,
       TextWrapping textWrap,
       double lineHeight,
       double indent)
    {
        _flowDirection = flowDirection;
        _textAlignment = textAlignment;
        _firstLineInParagraph = firstLineInParagraph;
        _alwaysCollapsible = alwaysCollapsible;
        _defaultTextRunProperties = defaultTextRunProperties;
        _textWrap = textWrap;
        _lineHeight = lineHeight;
        _indent = indent;
    }

    public override FlowDirection FlowDirection
    {
        get { return _flowDirection; }
    }

    public override TextAlignment TextAlignment
    {
        get { return _textAlignment; }
    }

    public override bool FirstLineInParagraph
    {
        get { return _firstLineInParagraph; }
    }

    public override bool AlwaysCollapsible
    {
        get { return _alwaysCollapsible; }
    }

    public override TextRunProperties DefaultTextRunProperties
    {
        get { return _defaultTextRunProperties; }
    }

    public override TextWrapping TextWrapping
    {
        get { return _textWrap; }
    }

    public override double LineHeight
    {
        get { return _lineHeight; }
    }

    public override double Indent
    {
        get { return _indent; }
    }

    public override TextMarkerProperties TextMarkerProperties
    {
        get { return null; }
    }

    public override double ParagraphIndent
    {
        get { return _paragraphIndent; }
    }

    private FlowDirection _flowDirection;
    private TextAlignment _textAlignment;
    private bool _firstLineInParagraph;
    private bool _alwaysCollapsible;
    private TextRunProperties _defaultTextRunProperties;
    private TextWrapping _textWrap;
    private double _indent;
    private double _paragraphIndent;
    private double _lineHeight;
}

现在 TextSource 实现:

public class CustomTextSourceRun
{
    public string Text;
    public bool IsSuperscript;
    public bool IsEndParagraph;
    public int Length { get { return IsEndParagraph ? 1 : Text.Length; } }
}


class CustomTextSource : TextSource
{
    public List<CustomTextSourceRun> Runs = new List<CustomTextSourceRun>();

    public override TextRun GetTextRun(int textSourceCharacterIndex)
    {
        int pos = 0;
        foreach (var currentRun in Runs)
        {
            if (textSourceCharacterIndex < pos + currentRun.Length)
            {
                if (currentRun.IsEndParagraph)
                {
                    return new TextEndOfParagraph(1);
                }

                var props =
                    new CustomTextRunProperties(currentRun.IsSuperscript);

                return new TextCharacters(
                    currentRun.Text,
                    textSourceCharacterIndex - pos,
                    currentRun.Length - (textSourceCharacterIndex - pos),
                    props);


            }
            pos += currentRun.Length;
        }

        // Return an end-of-paragraph if no more text source.
        return new TextEndOfParagraph(1);
    }

    public override TextSpan<CultureSpecificCharacterBufferRange> GetPrecedingText(int textSourceCharacterIndexLimit)
    {
        throw new Exception("The method or operation is not implemented.");
    }

    public override int GetTextEffectCharacterIndexFromTextSourceCharacterIndex(int textSourceCharacterIndex)
    {
        throw new Exception("The method or operation is not implemented.");
    }

    public int Length
    {
        get
        {
            int r = 0;
            foreach (var currentRun in Runs)
            {
                r += currentRun.Length;
            }
            return r;
        }
    }
}

剩下要做的就是初始化 CustomTextSource 并绘制文本:

     var textStore = new CustomTextSource();
     textStore.Runs.Add(new CustomTextSourceRun() { Text = "3" });
     textStore.Runs.Add(new CustomTextSourceRun() { Text = "rd", IsSuperscript = true });
     textStore.Runs.Add(new CustomTextSourceRun() { IsEndParagraph = true });
     textStore.Runs.Add(new CustomTextSourceRun() { Text = "4" });
     textStore.Runs.Add(new CustomTextSourceRun() { Text = "th", IsSuperscript = true });

     int textStorePosition = 0;
     System.Windows.Point linePosition = new System.Windows.Point(0, 0); 

     textDest = new DrawingGroup();
     DrawingContext dc = textDest.Open();

     TextFormatter formatter = TextFormatter.Create();

     while (textStorePosition < textStore.Length)
     {
        using (TextLine myTextLine = formatter.FormatLine(
            textStore,
            textStorePosition,
            96*6,
            new GenericTextParagraphProperties(FlowDirection.LeftToRight,
                TextAlignment.Left,true,false, new CustomTextRunProperties(false), TextWrapping.Wrap,
                30,0), null))
        {
            myTextLine.Draw(dc, linePosition, InvertAxes.None);
            textStorePosition += myTextLine.Length;
            linePosition.Y += myTextLine.Height;
        }
     }

     dc.Close();

就是这样 - 我们在绘图上下文中有上标文本。

于 2010-07-07T11:48:23.003 回答
0

根本没有办法FormattedText,请参阅此处的完整参考:

http://msdn.microsoft.com/en-us/library/system.windows.media.formattedtext_members.aspx

TextBlock正如您已经发现的那样,您可以使用它:

在 wpf 中的格式化文本中设置上标和下标

或者您可以简单地制作FormattedText较小的 ( SetFontSize) 并手动将其放置在上方/下方。

如果您可以就您正在使用的情况FormattedText或您试图解决的问题或您为什么不能使用 a提供更多背景TextBlock信息,请回复此答案,我们将很乐意为您提供更具体的示例.

希望有帮助!

于 2010-07-06T19:35:32.153 回答