FormattedText类中的下标/上标?

ste*_*wpf 4 wpf superscript subscript formatted-text

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

Nir*_*Nir 11

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

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

如何使用TextFormatter

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

TextSource是一个抽象类,你要继承它,并覆盖GetTextRun这只是返回一个方法TextRun对象,它是在提供的字符位置.

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

TextRunProperties遗憾的是,格式化信息位于对象中,这是您必须子类化的另一个抽象类.

TextRunProperties有一个TypographyProperties类型的属性TextRunTypographyProperties.

TextRunTypographyProperties 是你需要子类的另一个抽象类.

最后TextRunTypographyPropertiesVariants像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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

段落格式的类似类(从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;
}
Run Code Online (Sandbox Code Playgroud)

现在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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

剩下要做的就是初始化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();
Run Code Online (Sandbox Code Playgroud)

就是这样 - 我们在绘图环境中有上标文本.