RichTextBox.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. using System.Drawing;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows.Documents;
  6. namespace System.Windows.Forms
  7. {
  8. /// <summary>
  9. /// Specifies how text in a <see cref="RichTextBox"/> is horizontally aligned.
  10. /// </summary>
  11. public enum TextAlign
  12. {
  13. /// <summary>
  14. /// The text is aligned to the left.
  15. /// </summary>
  16. Left,
  17. /// <summary>
  18. /// The text is aligned to the right.
  19. /// </summary>
  20. Right,
  21. /// <summary>
  22. /// The text is aligned in the center.
  23. /// </summary>
  24. Center,
  25. /// <summary>
  26. /// The text is justified.
  27. /// </summary>
  28. Justify
  29. }
  30. public class RichTextBox : Control
  31. {
  32. protected new System.Windows.Controls.RichTextBox control { get; }
  33. public string Rtf
  34. {
  35. get
  36. {
  37. using (var stream = new MemoryStream())
  38. {
  39. SaveFile(stream, RichTextBoxStreamType.RichText);
  40. return Encoding.UTF8.GetString(stream.ToArray());
  41. }
  42. }
  43. set
  44. {
  45. var documentBytes = Encoding.UTF8.GetBytes(value);
  46. using (var stream = new MemoryStream(documentBytes))
  47. {
  48. stream.Position = 0;
  49. LoadFile(stream, RichTextBoxStreamType.RichText);
  50. }
  51. }
  52. }
  53. private RichTextBoxScrollBars scrollBars;
  54. public RichTextBoxScrollBars ScrollBars
  55. {
  56. get => scrollBars;
  57. set
  58. {
  59. scrollBars = value;
  60. control.HorizontalScrollBarVisibility = value == RichTextBoxScrollBars.Horizontal || value == RichTextBoxScrollBars.Both ?
  61. Windows.Controls.ScrollBarVisibility.Visible : Windows.Controls.ScrollBarVisibility.Hidden;
  62. control.VerticalScrollBarVisibility = value == RichTextBoxScrollBars.Vertical || value == RichTextBoxScrollBars.Both ?
  63. Windows.Controls.ScrollBarVisibility.Visible : Windows.Controls.ScrollBarVisibility.Hidden;
  64. }
  65. }
  66. public bool ReadOnly
  67. {
  68. get => control.IsReadOnly;
  69. set => control.IsReadOnly = value;
  70. }
  71. public bool AcceptsTab
  72. {
  73. get => control.AcceptsTab;
  74. set => control.AcceptsTab = value;
  75. }
  76. public int BulletIndent { get; set; } // TODO?
  77. public bool DetectUrls { get; set; } // TODO?
  78. public bool HideSelection
  79. {
  80. get => !control.IsInactiveSelectionHighlightEnabled;
  81. set => control.IsInactiveSelectionHighlightEnabled = !value;
  82. }
  83. public Font SelectionFont
  84. {
  85. get
  86. {
  87. object tmp = control.Selection.GetPropertyValue(Inline.FontFamilyProperty);
  88. var family = tmp == DependencyProperty.UnsetValue ? this.control.FontFamily : (Media.FontFamily)tmp;
  89. tmp = control.Selection.GetPropertyValue(Inline.FontSizeProperty);
  90. var size = tmp == DependencyProperty.UnsetValue ? this.control.FontSize : (double)tmp;
  91. tmp = control.Selection.GetPropertyValue(Inline.FontStyleProperty); ;
  92. var style = tmp == DependencyProperty.UnsetValue ? this.control.FontStyle : (FontStyle)tmp;
  93. tmp = control.Selection.GetPropertyValue(Inline.FontWeightProperty);
  94. var weight = tmp == DependencyProperty.UnsetValue ? this.control.FontWeight : (FontWeight)tmp;
  95. tmp = control.Selection.GetPropertyValue(Inline.TextDecorationsProperty);
  96. bool underline = false;
  97. bool strikeout = false;
  98. if (tmp is TextDecorationCollection deco)
  99. {
  100. underline = deco.Where(c => c.Location == TextDecorationLocation.Underline).Any();
  101. strikeout = deco.Where(c => c.Location == TextDecorationLocation.Strikethrough).Any();
  102. }
  103. return Helper.GetFont(DpiScale, family, size, style, weight, underline, strikeout);
  104. }
  105. set
  106. {
  107. Helper.SetFont(value, DpiScale, out var family, out var size, out var style, out var weight, out var deco);
  108. control.Selection.ApplyPropertyValue(Inline.FontFamilyProperty, family);
  109. control.Selection.ApplyPropertyValue(Inline.FontSizeProperty, size);
  110. control.Selection.ApplyPropertyValue(Inline.FontStyleProperty, style);
  111. control.Selection.ApplyPropertyValue(Inline.FontWeightProperty, weight);
  112. control.Selection.ApplyPropertyValue(Inline.TextDecorationsProperty, deco);
  113. }
  114. }
  115. public Color SelectionColor
  116. {
  117. get
  118. {
  119. object tmp = control.Selection.GetPropertyValue(Inline.ForegroundProperty);
  120. var color = tmp == DependencyProperty.UnsetValue ? this.control.Foreground : (System.Windows.Media.Brush)tmp;
  121. return Helper.GetColor(color);
  122. }
  123. set
  124. {
  125. control.Selection.ApplyPropertyValue(Inline.ForegroundProperty, Helper.GetBrush(value));
  126. }
  127. }
  128. public int SelectionCharOffset
  129. {
  130. get
  131. {
  132. object tmp = control.Selection.GetPropertyValue(Inline.BaselineAlignmentProperty);
  133. var baseline = tmp == DependencyProperty.UnsetValue ? BaselineAlignment.Baseline : (BaselineAlignment)tmp;
  134. if (baseline == BaselineAlignment.Subscript)
  135. return -4;
  136. if (baseline == BaselineAlignment.Superscript)
  137. return 4;
  138. return 0;
  139. }
  140. set
  141. {
  142. var baseline = BaselineAlignment.Baseline;
  143. if (value == -4)
  144. baseline = BaselineAlignment.Subscript;
  145. else if (value == 4)
  146. baseline = BaselineAlignment.Superscript;
  147. control.Selection.ApplyPropertyValue(Inline.BaselineAlignmentProperty, baseline);
  148. }
  149. }
  150. public bool SelectionBullet
  151. {
  152. get
  153. {
  154. var list = control.Document.Blocks
  155. .Where(x => x.ContentStart.CompareTo(control.Selection.End) != 1 && x.ContentEnd.CompareTo(control.Selection.Start) != -1)
  156. .FirstOrDefault() as List;
  157. if (list != null)
  158. return list.MarkerStyle != TextMarkerStyle.None;
  159. return false;
  160. }
  161. set
  162. {
  163. EditingCommands.ToggleBullets.Execute(null, control);
  164. }
  165. }
  166. public TextAlign SelectionAlignment
  167. {
  168. get
  169. {
  170. object tmp = control.Selection.GetPropertyValue(Paragraph.TextAlignmentProperty);
  171. var textAlign = tmp == DependencyProperty.UnsetValue ? TextAlignment.Left : (TextAlignment)tmp;
  172. return (TextAlign)textAlign;
  173. }
  174. set
  175. {
  176. control.Selection.ApplyPropertyValue(Paragraph.TextAlignmentProperty, (TextAlignment)value);
  177. }
  178. }
  179. public string SelectedText
  180. {
  181. get => control.Selection.Text;
  182. set => control.Selection.Text = value;
  183. }
  184. public bool Modified { get; set; }
  185. public event EventHandler SelectionChanged;
  186. private string GetFormat(RichTextBoxStreamType fileType)
  187. {
  188. return fileType switch
  189. {
  190. RichTextBoxStreamType.RichText => DataFormats.Rtf,
  191. RichTextBoxStreamType.RichNoOleObjs => DataFormats.Rtf,
  192. RichTextBoxStreamType.UnicodePlainText => DataFormats.UnicodeText,
  193. _ => DataFormats.Text
  194. };
  195. }
  196. protected virtual void OnSelectionChanged(EventArgs e) => SelectionChanged?.Invoke(this, e);
  197. public void LoadFile(Stream stream, RichTextBoxStreamType fileType)
  198. {
  199. control.SelectAll();
  200. control.Selection.Load(stream, GetFormat(fileType));
  201. control.Selection.Select(control.Selection.End, control.Selection.End);
  202. }
  203. public void LoadFile(string path, RichTextBoxStreamType fileType)
  204. {
  205. using (var fs = File.OpenRead(path))
  206. LoadFile(fs, fileType);
  207. }
  208. public void LoadFile(string path) => LoadFile(path, RichTextBoxStreamType.RichText);
  209. public void SaveFile(Stream stream, RichTextBoxStreamType fileType)
  210. {
  211. control.SelectAll();
  212. control.Selection.Save(stream, GetFormat(fileType));
  213. }
  214. public void SaveFile(string path, RichTextBoxStreamType fileType)
  215. {
  216. using (var fs = File.OpenWrite(path))
  217. SaveFile(fs, fileType);
  218. }
  219. public void SaveFile(string path) => SaveFile(path, RichTextBoxStreamType.RichText);
  220. public void Undo() => control.Undo();
  221. public void Redo() => control.Redo();
  222. public void SetSelectionFont(string fontName)
  223. {
  224. control.Selection.ApplyPropertyValue(Inline.FontFamilyProperty, fontName);
  225. }
  226. public void SetSelectionSize(int fontSize)
  227. {
  228. control.Selection.ApplyPropertyValue(Inline.FontSizeProperty, fontSize * 96 / 72.0);
  229. }
  230. public void SetSelectionBold(bool value)
  231. {
  232. control.Selection.ApplyPropertyValue(Inline.FontWeightProperty, value ? FontWeights.Bold : FontWeights.Normal);
  233. }
  234. public void SetSelectionItalic(bool value)
  235. {
  236. control.Selection.ApplyPropertyValue(Inline.FontStyleProperty, value ? FontStyles.Italic : FontStyles.Normal);
  237. }
  238. public void SetSelectionUnderline(bool value)
  239. {
  240. control.Selection.ApplyPropertyValue(Inline.TextDecorationsProperty, value ? TextDecorations.Underline : new TextDecorationCollection());
  241. }
  242. public void SelectAll() => control.SelectAll();
  243. public RichTextBox()
  244. {
  245. control = new();
  246. SetControl(control);
  247. control.SelectionChanged += (s, e) => OnSelectionChanged(e);
  248. control.TextChanged += (s, e) =>
  249. {
  250. OnTextChanged(e);
  251. Modified = true;
  252. };
  253. control.PreviewDragEnter += (s, e) => OnDragEnter(Helper.GetDragEventArgs(control, e));
  254. control.PreviewDragLeave += (s, e) => OnDragLeave(Helper.GetDragEventArgs(control, e));
  255. control.PreviewDragOver += (s, e) =>
  256. {
  257. var args = Helper.GetDragEventArgs(control, e);
  258. args.Effect = DragDropEffects.None;
  259. OnDragOver(args);
  260. e.Effects = (Windows.DragDropEffects)args.Effect;
  261. e.Handled = true;
  262. };
  263. }
  264. }
  265. }