using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Windows.Documents; namespace System.Windows.Forms { /// /// Specifies how text in a is horizontally aligned. /// public enum TextAlign { /// /// The text is aligned to the left. /// Left, /// /// The text is aligned to the right. /// Right, /// /// The text is aligned in the center. /// Center, /// /// The text is justified. /// Justify } public class RichTextBox : Control { protected new System.Windows.Controls.RichTextBox control { get; } public string Rtf { get { using (var stream = new MemoryStream()) { SaveFile(stream, RichTextBoxStreamType.RichText); return Encoding.UTF8.GetString(stream.ToArray()); } } set { var documentBytes = Encoding.UTF8.GetBytes(value); using (var stream = new MemoryStream(documentBytes)) { stream.Position = 0; LoadFile(stream, RichTextBoxStreamType.RichText); } } } private RichTextBoxScrollBars scrollBars; public RichTextBoxScrollBars ScrollBars { get => scrollBars; set { scrollBars = value; control.HorizontalScrollBarVisibility = value == RichTextBoxScrollBars.Horizontal || value == RichTextBoxScrollBars.Both ? Windows.Controls.ScrollBarVisibility.Visible : Windows.Controls.ScrollBarVisibility.Hidden; control.VerticalScrollBarVisibility = value == RichTextBoxScrollBars.Vertical || value == RichTextBoxScrollBars.Both ? Windows.Controls.ScrollBarVisibility.Visible : Windows.Controls.ScrollBarVisibility.Hidden; } } public bool ReadOnly { get => control.IsReadOnly; set => control.IsReadOnly = value; } public bool AcceptsTab { get => control.AcceptsTab; set => control.AcceptsTab = value; } public int BulletIndent { get; set; } // TODO? public bool DetectUrls { get; set; } // TODO? public bool HideSelection { get => !control.IsInactiveSelectionHighlightEnabled; set => control.IsInactiveSelectionHighlightEnabled = !value; } public Font SelectionFont { get { object tmp = control.Selection.GetPropertyValue(Inline.FontFamilyProperty); var family = tmp == DependencyProperty.UnsetValue ? this.control.FontFamily : (Media.FontFamily)tmp; tmp = control.Selection.GetPropertyValue(Inline.FontSizeProperty); var size = tmp == DependencyProperty.UnsetValue ? this.control.FontSize : (double)tmp; tmp = control.Selection.GetPropertyValue(Inline.FontStyleProperty); ; var style = tmp == DependencyProperty.UnsetValue ? this.control.FontStyle : (FontStyle)tmp; tmp = control.Selection.GetPropertyValue(Inline.FontWeightProperty); var weight = tmp == DependencyProperty.UnsetValue ? this.control.FontWeight : (FontWeight)tmp; tmp = control.Selection.GetPropertyValue(Inline.TextDecorationsProperty); bool underline = false; bool strikeout = false; if (tmp is TextDecorationCollection deco) { underline = deco.Where(c => c.Location == TextDecorationLocation.Underline).Any(); strikeout = deco.Where(c => c.Location == TextDecorationLocation.Strikethrough).Any(); } return Helper.GetFont(DpiScale, family, size, style, weight, underline, strikeout); } set { Helper.SetFont(value, DpiScale, out var family, out var size, out var style, out var weight, out var deco); control.Selection.ApplyPropertyValue(Inline.FontFamilyProperty, family); control.Selection.ApplyPropertyValue(Inline.FontSizeProperty, size); control.Selection.ApplyPropertyValue(Inline.FontStyleProperty, style); control.Selection.ApplyPropertyValue(Inline.FontWeightProperty, weight); control.Selection.ApplyPropertyValue(Inline.TextDecorationsProperty, deco); } } public Color SelectionColor { get { object tmp = control.Selection.GetPropertyValue(Inline.ForegroundProperty); var color = tmp == DependencyProperty.UnsetValue ? this.control.Foreground : (System.Windows.Media.Brush)tmp; return Helper.GetColor(color); } set { control.Selection.ApplyPropertyValue(Inline.ForegroundProperty, Helper.GetBrush(value)); } } public int SelectionCharOffset { get { object tmp = control.Selection.GetPropertyValue(Inline.BaselineAlignmentProperty); var baseline = tmp == DependencyProperty.UnsetValue ? BaselineAlignment.Baseline : (BaselineAlignment)tmp; if (baseline == BaselineAlignment.Subscript) return -4; if (baseline == BaselineAlignment.Superscript) return 4; return 0; } set { var baseline = BaselineAlignment.Baseline; if (value == -4) baseline = BaselineAlignment.Subscript; else if (value == 4) baseline = BaselineAlignment.Superscript; control.Selection.ApplyPropertyValue(Inline.BaselineAlignmentProperty, baseline); } } public bool SelectionBullet { get { var list = control.Document.Blocks .Where(x => x.ContentStart.CompareTo(control.Selection.End) != 1 && x.ContentEnd.CompareTo(control.Selection.Start) != -1) .FirstOrDefault() as List; if (list != null) return list.MarkerStyle != TextMarkerStyle.None; return false; } set { EditingCommands.ToggleBullets.Execute(null, control); } } public TextAlign SelectionAlignment { get { object tmp = control.Selection.GetPropertyValue(Paragraph.TextAlignmentProperty); var textAlign = tmp == DependencyProperty.UnsetValue ? TextAlignment.Left : (TextAlignment)tmp; return (TextAlign)textAlign; } set { control.Selection.ApplyPropertyValue(Paragraph.TextAlignmentProperty, (TextAlignment)value); } } public string SelectedText { get => control.Selection.Text; set => control.Selection.Text = value; } public bool Modified { get; set; } public event EventHandler SelectionChanged; private string GetFormat(RichTextBoxStreamType fileType) { return fileType switch { RichTextBoxStreamType.RichText => DataFormats.Rtf, RichTextBoxStreamType.RichNoOleObjs => DataFormats.Rtf, RichTextBoxStreamType.UnicodePlainText => DataFormats.UnicodeText, _ => DataFormats.Text }; } protected virtual void OnSelectionChanged(EventArgs e) => SelectionChanged?.Invoke(this, e); public void LoadFile(Stream stream, RichTextBoxStreamType fileType) { control.SelectAll(); control.Selection.Load(stream, GetFormat(fileType)); control.Selection.Select(control.Selection.End, control.Selection.End); } public void LoadFile(string path, RichTextBoxStreamType fileType) { using (var fs = File.OpenRead(path)) LoadFile(fs, fileType); } public void LoadFile(string path) => LoadFile(path, RichTextBoxStreamType.RichText); public void SaveFile(Stream stream, RichTextBoxStreamType fileType) { control.SelectAll(); control.Selection.Save(stream, GetFormat(fileType)); } public void SaveFile(string path, RichTextBoxStreamType fileType) { using (var fs = File.OpenWrite(path)) SaveFile(fs, fileType); } public void SaveFile(string path) => SaveFile(path, RichTextBoxStreamType.RichText); public void Undo() => control.Undo(); public void Redo() => control.Redo(); public void SetSelectionFont(string fontName) { control.Selection.ApplyPropertyValue(Inline.FontFamilyProperty, fontName); } public void SetSelectionSize(int fontSize) { control.Selection.ApplyPropertyValue(Inline.FontSizeProperty, fontSize * 96 / 72.0); } public void SetSelectionBold(bool value) { control.Selection.ApplyPropertyValue(Inline.FontWeightProperty, value ? FontWeights.Bold : FontWeights.Normal); } public void SetSelectionItalic(bool value) { control.Selection.ApplyPropertyValue(Inline.FontStyleProperty, value ? FontStyles.Italic : FontStyles.Normal); } public void SetSelectionUnderline(bool value) { control.Selection.ApplyPropertyValue(Inline.TextDecorationsProperty, value ? TextDecorations.Underline : new TextDecorationCollection()); } public void SelectAll() => control.SelectAll(); public RichTextBox() { control = new(); SetControl(control); control.SelectionChanged += (s, e) => OnSelectionChanged(e); control.TextChanged += (s, e) => { OnTextChanged(e); Modified = true; }; control.PreviewDragEnter += (s, e) => OnDragEnter(Helper.GetDragEventArgs(control, e)); control.PreviewDragLeave += (s, e) => OnDragLeave(Helper.GetDragEventArgs(control, e)); control.PreviewDragOver += (s, e) => { var args = Helper.GetDragEventArgs(control, e); args.Effect = DragDropEffects.None; OnDragOver(args); e.Effects = (Windows.DragDropEffects)args.Effect; e.Handled = true; }; } } }