我正在使用 FormattedText 类创建文本 - 但是在使用此类时如何下标或上标文本?我找到了使用 TextBlock 时如何执行此操作的解决方案,但我使用的是 FormattedText 而不是 TextBlock ):感谢您的任何提示!
2 回答
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();
就是这样 - 我们在绘图上下文中有上标文本。
根本没有办法FormattedText
,请参阅此处的完整参考:
http://msdn.microsoft.com/en-us/library/system.windows.media.formattedtext_members.aspx
TextBlock
正如您已经发现的那样,您可以使用它:
或者您可以简单地制作FormattedText
较小的 ( SetFontSize
) 并手动将其放置在上方/下方。
如果您可以就您正在使用的情况FormattedText
或您试图解决的问题或您为什么不能使用 a提供更多背景TextBlock
信息,请回复此答案,我们将很乐意为您提供更具体的示例.
希望有帮助!