using AntdUI; using System; using System.ComponentModel; using System.Drawing; using System.Threading.Tasks; using System.Windows.Forms; namespace JinYuan.ControlLib { public partial class CustomRichTextBox : RichTextBox { private Color darkBackColor = Color.Black; private Color lightBackColor = Color.White; private Color darkForeColor = Color.White; private Color lightForeColor = Color.Black; private Color darkBorderColor = Color.FromArgb(64, 64, 64); private Color lightBorderColor = Color.FromArgb(217, 217, 217); private bool isDarkTheme; private const int BatchSize = 5000; private bool isUpdatingTheme = false; private bool isInitialized = false; public CustomRichTextBox() { BorderStyle = BorderStyle.None; SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); // 在句柄创建后初始化主题 HandleCreated += CustomRichTextBox_HandleCreated; } private void CustomRichTextBox_HandleCreated(object sender, EventArgs e) { if (!isInitialized) { isInitialized = true; InitializeThemeAsync(); } } private async void InitializeThemeAsync() { try { await UpdateThemeAsync(Config.IsDark); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Theme initialization failed: {ex.Message}"); } } public async Task UpdateThemeAsync(bool isDark) { if (isDarkTheme == isDark || isUpdatingTheme || !IsHandleCreated) return; isUpdatingTheme = true; isDarkTheme = isDark; try { if (InvokeRequired) { await Task.Run(() => { Invoke((MethodInvoker)(() => UpdateThemeInternal())); }); } else { UpdateThemeInternal(); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Theme update failed: {ex.Message}"); } finally { isUpdatingTheme = false; } } private void UpdateThemeInternal() { if (!IsHandleCreated) return; BackColor = isDarkTheme ? darkBackColor : lightBackColor; ForeColor = isDarkTheme ? darkForeColor : lightForeColor; SuspendLayout(); try { int visibleStart = GetCharIndexFromPosition(new Point(0, 0)); int visibleEnd = GetCharIndexFromPosition(new Point(ClientSize.Width, ClientSize.Height)); // Update visible text first UpdateTextColors(visibleStart, visibleEnd - visibleStart); // Then update the rest in batches for (int i = 0; i < TextLength; i += BatchSize) { if (i >= visibleStart && i < visibleEnd) continue; int length = Math.Min(BatchSize, TextLength - i); UpdateTextColors(i, length); if (i % (BatchSize * 10) == 0) Application.DoEvents(); } } finally { ResumeLayout(); } Invalidate(); } private void UpdateTextColors(int start, int length) { if (start < 0 || length <= 0 || start + length > TextLength) return; Select(start, length); SelectionColor = ForeColor; SelectionBackColor = BackColor; } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); using (var pen = new Pen(isDarkTheme ? darkBorderColor : lightBorderColor)) { e.Graphics.DrawRectangle(pen, 0, 0, Width - 1, Height - 1); } } protected override void OnTextChanged(EventArgs e) { base.OnTextChanged(e); if (!isUpdatingTheme && TextLength > 0 && IsHandleCreated) { int start = TextLength - 1; int length = 1; if (start < 0) start = 0; if (start + length > TextLength) length = TextLength - start; UpdateTextColors(start, length); SelectionLength = 0; SelectionStart = TextLength; } } [Browsable(true)] [Category("Appearance")] [DefaultValue(typeof(Color), "30, 30, 30")] public Color DarkBackColor { get => darkBackColor; set { if (darkBackColor != value) { darkBackColor = value; if (isDarkTheme && IsHandleCreated) SafeRefreshTheme(); } } } [Browsable(true)] [Category("Appearance")] [DefaultValue(typeof(Color), "White")] public Color LightBackColor { get => lightBackColor; set { if (lightBackColor != value) { lightBackColor = value; if (!isDarkTheme && IsHandleCreated) SafeRefreshTheme(); } } } [Browsable(true)] [Category("Appearance")] [DefaultValue(typeof(Color), "White")] public Color DarkForeColor { get => darkForeColor; set { if (darkForeColor != value) { darkForeColor = value; if (isDarkTheme && IsHandleCreated) SafeRefreshTheme(); } } } [Browsable(true)] [Category("Appearance")] [DefaultValue(typeof(Color), "Black")] public Color LightForeColor { get => lightForeColor; set { if (lightForeColor != value) { lightForeColor = value; if (!isDarkTheme && IsHandleCreated) SafeRefreshTheme(); } } } [Browsable(true)] [Category("Appearance")] [DefaultValue(typeof(Color), "64, 64, 64")] public Color DarkBorderColor { get => darkBorderColor; set { if (darkBorderColor != value) { darkBorderColor = value; if (isDarkTheme && IsHandleCreated) Invalidate(); } } } [Browsable(true)] [Category("Appearance")] [DefaultValue(typeof(Color), "217, 217, 217")] public Color LightBorderColor { get => lightBorderColor; set { if (lightBorderColor != value) { lightBorderColor = value; if (!isDarkTheme && IsHandleCreated) Invalidate(); } } } private async void SafeRefreshTheme() { try { await RefreshThemeAsync(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Theme refresh failed: {ex.Message}"); } } public async Task RefreshThemeAsync() { if (!IsHandleCreated) return; await UpdateThemeAsync(isDarkTheme); } } } //public partial class CustomRichTextBox : RichTextBox //{ // private Color darkBackColor = Color.Black; // private Color lightBackColor = Color.White; // private Color darkForeColor = Color.White; // private Color lightForeColor = Color.Black; // private Color darkBorderColor = Color.FromArgb(64, 64, 64); // private Color lightBorderColor = Color.FromArgb(217, 217, 217); // private bool isDarkTheme; // private const int BatchSize = 5000; // 每批处理的字符数 // private bool isUpdatingTheme = false; // public CustomRichTextBox() // { // BorderStyle = BorderStyle.None; // SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); // InitializeThemeAsync(); // } // private async void InitializeThemeAsync() // { // await UpdateThemeAsync(Config.IsDark); // } // public async Task UpdateThemeAsync(bool isDark) // { // if (isDarkTheme == isDark || isUpdatingTheme) return; // isUpdatingTheme = true; // isDarkTheme = isDark; // try // { // await Task.Run(async () => // { // await InvokeAsync(() => // { // BackColor = isDark ? darkBackColor : lightBackColor; // ForeColor = isDark ? darkForeColor : lightForeColor; // SuspendLayout(); // try // { // int visibleStart = GetCharIndexFromPosition(new Point(0, 0)); // int visibleEnd = GetCharIndexFromPosition(new Point(ClientSize.Width, ClientSize.Height)); // // Update visible text first // UpdateTextColors(visibleStart, visibleEnd - visibleStart); // // Then update the rest in batches // for (int i = 0; i < TextLength; i += BatchSize) // { // if (i >= visibleStart && i < visibleEnd) continue; // Skip already updated visible part // int length = Math.Min(BatchSize, TextLength - i); // UpdateTextColors(i, length); // if (i % (BatchSize * 10) == 0) Application.DoEvents(); // } // } // finally // { // ResumeLayout(); // } // Invalidate(); // }); // }); // } // finally // { // isUpdatingTheme = false; // } // } // private void UpdateTextColors(int start, int length) // { // Select(start, length); // SelectionColor = ForeColor; // SelectionBackColor = BackColor; // } // protected override void OnPaint(PaintEventArgs e) // { // base.OnPaint(e); // using (var pen = new Pen(isDarkTheme ? darkBorderColor : lightBorderColor)) // { // e.Graphics.DrawRectangle(pen, 0, 0, Width - 1, Height - 1); // } // } // protected override void OnTextChanged(EventArgs e) // { // base.OnTextChanged(e); // if (!isUpdatingTheme && TextLength > 0) // { // int start = TextLength - 1; // int length = 1; // if (start < 0) start = 0; // if (start + length > TextLength) length = TextLength - start; // UpdateTextColors(start, length); // SelectionLength = 0; // SelectionStart = TextLength; // } // } // [Browsable(true)] // [Category("Appearance")] // [DefaultValue(typeof(Color), "30, 30, 30")] // public Color DarkBackColor // { // get => darkBackColor; // set { darkBackColor = value; if (isDarkTheme) RefreshThemeAsync(); } // } // [Browsable(true)] // [Category("Appearance")] // [DefaultValue(typeof(Color), "White")] // public Color LightBackColor // { // get => lightBackColor; // set { lightBackColor = value; if (!isDarkTheme) RefreshThemeAsync(); } // } // [Browsable(true)] // [Category("Appearance")] // [DefaultValue(typeof(Color), "White")] // public Color DarkForeColor // { // get => darkForeColor; // set { darkForeColor = value; if (isDarkTheme) RefreshThemeAsync(); } // } // [Browsable(true)] // [Category("Appearance")] // [DefaultValue(typeof(Color), "Black")] // public Color LightForeColor // { // get => lightForeColor; // set { lightForeColor = value; if (!isDarkTheme) RefreshThemeAsync(); } // } // [Browsable(true)] // [Category("Appearance")] // [DefaultValue(typeof(Color), "64, 64, 64")] // public Color DarkBorderColor // { // get => darkBorderColor; // set { darkBorderColor = value; if (isDarkTheme) Invalidate(); } // } // [Browsable(true)] // [Category("Appearance")] // [DefaultValue(typeof(Color), "217, 217, 217")] // public Color LightBorderColor // { // get => lightBorderColor; // set { lightBorderColor = value; if (!isDarkTheme) Invalidate(); } // } // public async Task RefreshThemeAsync() // { // await UpdateThemeAsync(isDarkTheme); // } // private Task InvokeAsync(Action action) // { // return Task.Factory.FromAsync(BeginInvoke(action), EndInvoke); // } //}