richtexbox 如何从 winforms 上的事件侦听器附加文本异步?

How richtexbox can append text async from event listener on winforms?

如何异步使用richtextbox?例如,我有一个 class 和一个记录某种计算的事件

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ExampleProject
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {   
            //I subscribe to an event that often sends messages 
            //and I want to display
            var c = new Core();
            c.Notify += DisplayMessage;
            c.ExampleMethod();
        }

        private void DisplayMessage(object sender, LogEventArgs e)
        {    //When a event arrives, transfer to richTextBox1
            richTextBox1.AppendText("\r\n" + e.Date.ToString("dd/MM/yyyy HH:mm:ss "), Color.SlateGray);
            richTextBox1.AppendText(e.Message, Color.Blue);
            richTextBox1.SelectionStart = richTextBox1.Text.Length;
            richTextBox1.ScrollToCaret();
            
        }
    }

    class Core
    {
        public delegate void LogHandler(object sender, LogEventArgs e);
        public event LogHandler Notify;

        //
        public void ExampleMethod()
        {   
            //generate messages with a pause in a random value
            var rand = new Random();
            
            for (int i = 1; i < 10000; i++)
            {   var pause = rand.Next(50, 2000);
                Thread.Sleep(pause);
                Notify?.Invoke(this, new LogEventArgs($"logged {i} pause in miliseconds {pause}", DateTime.Now, MessageType.Notice));
            }
        }
    }   //The class in which log messages are placed
        class LogEventArgs
    {

        public string Message { get; }

        public DateTime Date { get; }
        public MessageType MessageType { get; }


        public LogEventArgs(string mes, DateTime date, MessageType messageType)
        {
            Message = mes;
            Date = date;
            MessageType = messageType;
        }
    }

    enum MessageType
    {
        Notice,
        Warning,
        Error,
    }
     //Extension method to set line colors in RichTextBox
    public static class RichTextBoxExtensions
    {
        public static void AppendText(this RichTextBox box, string text, Color color)
        {
            box.SelectionStart = box.TextLength;
            box.SelectionLength = 0;

            box.SelectionColor = color;
            box.AppendText(text);
            box.SelectionColor = box.ForeColor;
        }
    }


}

尝试了 backgroundworker、task、synchronization... 的选项,但没有结果。我很惊讶 WinForms 已经存在了很多年,而 Microsoft 还没有向它们添加异步操作,例如 AppendTextAsync()。如何强制将文本异步添加到 richtextbox?

在您的表单上添加另一个文本框

将此代码粘贴到 Form1.cs 中所有内容的顶部:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ExampleProject
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            var c = new Core();
            c.Notify += DisplayMessage;
            await c.ExampleMethod();
        }

        private void DisplayMessage(object sender, LogEventArgs e)
        {
            richTextBox1.AppendText("\r\n" + e.Date.ToString("dd/MM/yyyy HH:mm:ss "), Color.SlateGray);
            richTextBox1.AppendText(e.Message, Color.Blue);
            richTextBox1.SelectionStart = richTextBox1.Text.Length;
            richTextBox1.ScrollToCaret();
            
        }
    }

    class Core
    {
        public delegate void LogHandler(object sender, LogEventArgs e);
        public event LogHandler Notify;


        public async Task ExampleMethod()
        {
            var rand = new Random();

            for (int i = 1; i < 10000; i++)
            {   var pause = rand.Next(50, 200);
                await Task.Delay(pause);
                Notify?.Invoke(this, new LogEventArgs($"logged {i} pause in miliseconds {pause}", DateTime.Now, MessageType.Notice));
            }
        }
    }
        class LogEventArgs
    {

        public string Message { get; }

        public DateTime Date { get; }
        public MessageType MessageType { get; }


        public LogEventArgs(string mes, DateTime date, MessageType messageType)
        {
            Message = mes;
            Date = date;
            MessageType = messageType;
        }
    }

    enum MessageType
    {
        Notice,
        Warning,
        Error,
    }
    public static class RichTextBoxExtensions
    {
        public static void AppendText(this RichTextBox box, string text, Color color)
        {
            box.SelectionStart = box.TextLength;
            box.SelectionLength = 0;

            box.SelectionColor = color;
            box.AppendText(text);
            box.SelectionColor = box.ForeColor;
        }
    }


}

运行 它,单击按钮,然后在另一个文本框中继续输入 - 它保持响应等等。我不知道你需要等多久才能看到主要的减速,因为RTB 中的文本变得很大。但实际上您应该定期查看日志,这样您就不会在 RTB

中建立兆字节的文本

winforms 中的异步不是让控件使用某种异步方式进行更新;控件只能由创建它们的线程访问,因此与控件的任何交互我们通常要求该线程执行它(但我认为这是一个角度问题:如果后台线程要求 UI 线程更新一个控件然后它被异步完成后台线程正在做的任何工作) - 确保你对它们所做的访问是快速的,做你的繁重工作(API 调用?)使用异步方式然后调用以获取你的UI 更新控件的线程。