TextBlock.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using System.Reactive;
  5. using System.Reactive.Linq;
  6. using Avalonia.Data;
  7. using Avalonia.LogicalTree;
  8. using Avalonia.Media;
  9. using Avalonia.Metadata;
  10. namespace Avalonia.Controls
  11. {
  12. /// <summary>
  13. /// A control that displays a block of text.
  14. /// </summary>
  15. public class TextBlock : Control
  16. {
  17. /// <summary>
  18. /// Defines the <see cref="Background"/> property.
  19. /// </summary>
  20. public static readonly StyledProperty<IBrush> BackgroundProperty =
  21. Border.BackgroundProperty.AddOwner<TextBlock>();
  22. // TODO: Define these attached properties elswhere (e.g. on a Text class) and AddOwner
  23. // them into TextBlock.
  24. /// <summary>
  25. /// Defines the <see cref="FontFamily"/> property.
  26. /// </summary>
  27. public static readonly AttachedProperty<FontFamily> FontFamilyProperty =
  28. AvaloniaProperty.RegisterAttached<TextBlock, Control, FontFamily>(
  29. nameof(FontFamily),
  30. defaultValue: new FontFamily("Courier New"),
  31. inherits: true);
  32. /// <summary>
  33. /// Defines the <see cref="FontSize"/> property.
  34. /// </summary>
  35. public static readonly AttachedProperty<double> FontSizeProperty =
  36. AvaloniaProperty.RegisterAttached<TextBlock, Control, double>(
  37. nameof(FontSize),
  38. defaultValue: 12,
  39. inherits: true);
  40. /// <summary>
  41. /// Defines the <see cref="FontStyle"/> property.
  42. /// </summary>
  43. public static readonly AttachedProperty<FontStyle> FontStyleProperty =
  44. AvaloniaProperty.RegisterAttached<TextBlock, Control, FontStyle>(
  45. nameof(FontStyle),
  46. inherits: true);
  47. /// <summary>
  48. /// Defines the <see cref="FontWeight"/> property.
  49. /// </summary>
  50. public static readonly AttachedProperty<FontWeight> FontWeightProperty =
  51. AvaloniaProperty.RegisterAttached<TextBlock, Control, FontWeight>(
  52. nameof(FontWeight),
  53. inherits: true,
  54. defaultValue: FontWeight.Normal);
  55. /// <summary>
  56. /// Defines the <see cref="Foreground"/> property.
  57. /// </summary>
  58. public static readonly AttachedProperty<IBrush> ForegroundProperty =
  59. AvaloniaProperty.RegisterAttached<TextBlock, Control, IBrush>(
  60. nameof(Foreground),
  61. new SolidColorBrush(0xff000000),
  62. inherits: true);
  63. /// <summary>
  64. /// Defines the <see cref="Text"/> property.
  65. /// </summary>
  66. public static readonly DirectProperty<TextBlock, string> TextProperty =
  67. AvaloniaProperty.RegisterDirect<TextBlock, string>(
  68. nameof(Text),
  69. o => o.Text,
  70. (o, v) => o.Text = v);
  71. /// <summary>
  72. /// Defines the <see cref="TextAlignment"/> property.
  73. /// </summary>
  74. public static readonly StyledProperty<TextAlignment> TextAlignmentProperty =
  75. AvaloniaProperty.Register<TextBlock, TextAlignment>(nameof(TextAlignment));
  76. /// <summary>
  77. /// Defines the <see cref="TextWrapping"/> property.
  78. /// </summary>
  79. public static readonly StyledProperty<TextWrapping> TextWrappingProperty =
  80. AvaloniaProperty.Register<TextBlock, TextWrapping>(nameof(TextWrapping));
  81. private string _text;
  82. private FormattedText _formattedText;
  83. private Size _constraint;
  84. /// <summary>
  85. /// Initializes static members of the <see cref="TextBlock"/> class.
  86. /// </summary>
  87. static TextBlock()
  88. {
  89. ClipToBoundsProperty.OverrideDefaultValue<TextBlock>(true);
  90. AffectsRender(ForegroundProperty);
  91. AffectsRender(FontWeightProperty);
  92. AffectsRender(FontSizeProperty);
  93. AffectsRender(FontStyleProperty);
  94. }
  95. /// <summary>
  96. /// Initializes a new instance of the <see cref="TextBlock"/> class.
  97. /// </summary>
  98. public TextBlock()
  99. {
  100. Observable.Merge(
  101. this.GetObservable(TextProperty).Select(_ => Unit.Default),
  102. this.GetObservable(TextAlignmentProperty).Select(_ => Unit.Default),
  103. this.GetObservable(FontSizeProperty).Select(_ => Unit.Default),
  104. this.GetObservable(FontStyleProperty).Select(_ => Unit.Default),
  105. this.GetObservable(FontWeightProperty).Select(_ => Unit.Default))
  106. .Subscribe(_ =>
  107. {
  108. InvalidateFormattedText();
  109. InvalidateMeasure();
  110. });
  111. }
  112. /// <summary>
  113. /// Gets or sets a brush used to paint the control's background.
  114. /// </summary>
  115. public IBrush Background
  116. {
  117. get { return GetValue(BackgroundProperty); }
  118. set { SetValue(BackgroundProperty, value); }
  119. }
  120. /// <summary>
  121. /// Gets or sets the text.
  122. /// </summary>
  123. [Content]
  124. public string Text
  125. {
  126. get { return _text; }
  127. set { SetAndRaise(TextProperty, ref _text, value); }
  128. }
  129. /// <summary>
  130. /// Gets or sets the font family.
  131. /// </summary>
  132. public FontFamily FontFamily
  133. {
  134. get { return GetValue(FontFamilyProperty); }
  135. set { SetValue(FontFamilyProperty, value); }
  136. }
  137. /// <summary>
  138. /// Gets or sets the font size.
  139. /// </summary>
  140. public double FontSize
  141. {
  142. get { return GetValue(FontSizeProperty); }
  143. set { SetValue(FontSizeProperty, value); }
  144. }
  145. /// <summary>
  146. /// Gets or sets the font style.
  147. /// </summary>
  148. public FontStyle FontStyle
  149. {
  150. get { return GetValue(FontStyleProperty); }
  151. set { SetValue(FontStyleProperty, value); }
  152. }
  153. /// <summary>
  154. /// Gets or sets the font weight.
  155. /// </summary>
  156. public FontWeight FontWeight
  157. {
  158. get { return GetValue(FontWeightProperty); }
  159. set { SetValue(FontWeightProperty, value); }
  160. }
  161. /// <summary>
  162. /// Gets or sets a brush used to paint the text.
  163. /// </summary>
  164. public IBrush Foreground
  165. {
  166. get { return GetValue(ForegroundProperty); }
  167. set { SetValue(ForegroundProperty, value); }
  168. }
  169. /// <summary>
  170. /// Gets the <see cref="FormattedText"/> used to render the text.
  171. /// </summary>
  172. public FormattedText FormattedText
  173. {
  174. get
  175. {
  176. if (_formattedText == null)
  177. {
  178. _formattedText = CreateFormattedText(_constraint);
  179. }
  180. return _formattedText;
  181. }
  182. }
  183. /// <summary>
  184. /// Gets or sets the control's text wrapping mode.
  185. /// </summary>
  186. public TextWrapping TextWrapping
  187. {
  188. get { return GetValue(TextWrappingProperty); }
  189. set { SetValue(TextWrappingProperty, value); }
  190. }
  191. /// <summary>
  192. /// Gets or sets the text alignment.
  193. /// </summary>
  194. public TextAlignment TextAlignment
  195. {
  196. get { return GetValue(TextAlignmentProperty); }
  197. set { SetValue(TextAlignmentProperty, value); }
  198. }
  199. /// <summary>
  200. /// Gets the value of the attached <see cref="FontFamilyProperty"/> on a control.
  201. /// </summary>
  202. /// <param name="control">The control.</param>
  203. /// <returns>The font family.</returns>
  204. public static FontFamily GetFontFamily(Control control)
  205. {
  206. return control.GetValue(FontFamilyProperty);
  207. }
  208. /// <summary>
  209. /// Gets the value of the attached <see cref="FontSizeProperty"/> on a control.
  210. /// </summary>
  211. /// <param name="control">The control.</param>
  212. /// <returns>The font family.</returns>
  213. public static double GetFontSize(Control control)
  214. {
  215. return control.GetValue(FontSizeProperty);
  216. }
  217. /// <summary>
  218. /// Gets the value of the attached <see cref="FontStyleProperty"/> on a control.
  219. /// </summary>
  220. /// <param name="control">The control.</param>
  221. /// <returns>The font family.</returns>
  222. public static FontStyle GetFontStyle(Control control)
  223. {
  224. return control.GetValue(FontStyleProperty);
  225. }
  226. /// <summary>
  227. /// Gets the value of the attached <see cref="FontWeightProperty"/> on a control.
  228. /// </summary>
  229. /// <param name="control">The control.</param>
  230. /// <returns>The font family.</returns>
  231. public static FontWeight GetFontWeight(Control control)
  232. {
  233. return control.GetValue(FontWeightProperty);
  234. }
  235. /// <summary>
  236. /// Gets the value of the attached <see cref="ForegroundProperty"/> on a control.
  237. /// </summary>
  238. /// <param name="control">The control.</param>
  239. /// <returns>The foreground.</returns>
  240. public static IBrush GetForeground(Control control)
  241. {
  242. return control.GetValue(ForegroundProperty);
  243. }
  244. /// <summary>
  245. /// Sets the value of the attached <see cref="FontFamilyProperty"/> on a control.
  246. /// </summary>
  247. /// <param name="control">The control.</param>
  248. /// <param name="value">The property value to set.</param>
  249. /// <returns>The font family.</returns>
  250. public static void SetFontFamily(Control control, string value)
  251. {
  252. control.SetValue(FontFamilyProperty, value);
  253. }
  254. /// <summary>
  255. /// Sets the value of the attached <see cref="FontSizeProperty"/> on a control.
  256. /// </summary>
  257. /// <param name="control">The control.</param>
  258. /// <param name="value">The property value to set.</param>
  259. /// <returns>The font family.</returns>
  260. public static void SetFontSize(Control control, double value)
  261. {
  262. control.SetValue(FontSizeProperty, value);
  263. }
  264. /// <summary>
  265. /// Sets the value of the attached <see cref="FontStyleProperty"/> on a control.
  266. /// </summary>
  267. /// <param name="control">The control.</param>
  268. /// <param name="value">The property value to set.</param>
  269. /// <returns>The font family.</returns>
  270. public static void SetFontStyle(Control control, FontStyle value)
  271. {
  272. control.SetValue(FontStyleProperty, value);
  273. }
  274. /// <summary>
  275. /// Sets the value of the attached <see cref="FontWeightProperty"/> on a control.
  276. /// </summary>
  277. /// <param name="control">The control.</param>
  278. /// <param name="value">The property value to set.</param>
  279. /// <returns>The font family.</returns>
  280. public static void SetFontWeight(Control control, FontWeight value)
  281. {
  282. control.SetValue(FontWeightProperty, value);
  283. }
  284. /// <summary>
  285. /// Sets the value of the attached <see cref="ForegroundProperty"/> on a control.
  286. /// </summary>
  287. /// <param name="control">The control.</param>
  288. /// <param name="value">The property value to set.</param>
  289. /// <returns>The font family.</returns>
  290. public static void SetForeground(Control control, IBrush value)
  291. {
  292. control.SetValue(ForegroundProperty, value);
  293. }
  294. /// <summary>
  295. /// Renders the <see cref="TextBlock"/> to a drawing context.
  296. /// </summary>
  297. /// <param name="context">The drawing context.</param>
  298. public override void Render(DrawingContext context)
  299. {
  300. var background = Background;
  301. if (background != null)
  302. {
  303. context.FillRectangle(background, new Rect(Bounds.Size));
  304. }
  305. FormattedText.Constraint = Bounds.Size;
  306. context.DrawText(Foreground, new Point(), FormattedText);
  307. }
  308. /// <summary>
  309. /// Creates the <see cref="FormattedText"/> used to render the text.
  310. /// </summary>
  311. /// <param name="constraint">The constraint of the text.</param>
  312. /// <returns>A <see cref="FormattedText"/> object.</returns>
  313. protected virtual FormattedText CreateFormattedText(Size constraint)
  314. {
  315. return new FormattedText
  316. {
  317. Constraint = constraint,
  318. Typeface = new Typeface(FontFamily, FontSize, FontStyle, FontWeight),
  319. Text = Text ?? string.Empty,
  320. TextAlignment = TextAlignment,
  321. Wrapping = TextWrapping,
  322. };
  323. }
  324. /// <summary>
  325. /// Invalidates <see cref="FormattedText"/>.
  326. /// </summary>
  327. protected void InvalidateFormattedText()
  328. {
  329. if (_formattedText != null)
  330. {
  331. _constraint = _formattedText.Constraint;
  332. _formattedText = null;
  333. }
  334. }
  335. /// <summary>
  336. /// Measures the control.
  337. /// </summary>
  338. /// <param name="availableSize">The available size for the control.</param>
  339. /// <returns>The desired size.</returns>
  340. protected override Size MeasureOverride(Size availableSize)
  341. {
  342. if (!string.IsNullOrEmpty(Text))
  343. {
  344. if (TextWrapping == TextWrapping.Wrap)
  345. {
  346. FormattedText.Constraint = new Size(availableSize.Width, double.PositiveInfinity);
  347. }
  348. else
  349. {
  350. FormattedText.Constraint = Size.Infinity;
  351. }
  352. return FormattedText.Measure();
  353. }
  354. return new Size();
  355. }
  356. protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
  357. {
  358. base.OnAttachedToLogicalTree(e);
  359. InvalidateFormattedText();
  360. InvalidateMeasure();
  361. }
  362. }
  363. }