龙空技术网

解决高频率刷新导致页面卡死使用用户控件和本地队列服务

小乖兽技术 171

前言:

今天兄弟们对“执行刷新操作时线程出现异常”大致比较着重,姐妹们都需要分析一些“执行刷新操作时线程出现异常”的相关内容。那么小编也在网络上汇集了一些关于“执行刷新操作时线程出现异常””的相关文章,希望看官们能喜欢,大家快快来了解一下吧!

winform页面防止页面卡死的方法有很多。这里介绍一种本人实战过的,可以用于高频率刷新页面控件的方法。仅供参考。其中运用到的技术主要包括: 队列使用、线程使用、委托刷新、用户控件;

首先:封装本地队列服务

使用泛型<T>,这样可以兼容多种数据类型刷新本地页面。主要代码如下:

/// <summary>/// 本地队列服务封装/// </summary>/// <typeparam name="T"></typeparam>public class QueueServer<T>{    public readonly object _lock = new object();    public readonly EventWaitHandle _wh = new AutoResetEvent(false);    public Queue<T> Queue;    private readonly Thread th;    //处理事件    public delegate void EventHandlerProcessing(T item);    public EventHandlerProcessing Processing;    //刷新队列剩余数量    public delegate void EnentHandlerRefresh(int Count);    public EnentHandlerRefresh Refreshing;    public QueueServer()    {        Queue = new Queue<T>();        th = new Thread(Work)        {            IsBackground = true        };    }    public void Start()    {        th.Start();    }    public void Stop()    {        if (th != null && th.ThreadState != ThreadState.Stopped)        {            th.Abort();        }    }    public QueueServer(EventHandlerProcessing Processing)    {        this.Processing += Processing;        th = new Thread(Work)        {            IsBackground = true        };    }    private void Work()    {        while (true)        {            T item = default(T);            lock (_lock)            {                if (Queue.Count > 0)                {                    item = Queue.Dequeue();                    Refreshing?.Invoke(Queue.Count);                    if (item == null)                    {                        return;                    }                }            }            if (item != null)            {                Processing?.Invoke(item);            }            else            {                _wh.WaitOne();            }        }    }    public void Enqueue(T item)    {        lock (_lock)        {            if (!Queue.Contains(item))            {                Queue.Enqueue(item);            }        }        _wh.Set();    }}

然后 新增用户控件MyRichTextBox;

主要代码如下,其中引用队列服务。在引用的组件中启动队列线程,注册刷新事件 Refresh到队列服务刷新事件。对外提供刷新方法RefreshRichText(string text),将需要刷新的文本加入队列。编译好后可以在工具栏中直接使用

[ToolboxItem(true)]public partial class MyRichTextBox : UserControl{    private readonly QueueServer<string> queueServer = new QueueServer<string>();    public override string Text    {        get        {            return richTextBox1.Text;        }        set        {            richTextBox1.Text = value;        }    }    public MyRichTextBox()    {        InitializeComponent();        queueServer.Processing += Refresh;        queueServer.Start();    }    private void richTextBox1_MouseUp(object sender, MouseEventArgs e)    {        if (e.Button == MouseButtons.Right)        {            contextMenuStrip1.Show(richTextBox1, new Point(e.X, e.Y));        }    }    private void toolStripMenuItem1_Click(object sender, EventArgs e)    {        richTextBox1.Clear();    }    public void AppendText(string msg)    {        richTextBox1.AppendText(msg);        richTextBox1.SelectionStart = richTextBox1.Text.Length;        richTextBox1.ScrollToCaret();    }    private void Refresh(string msg)    {        if (InvokeRequired)        {            Invoke(new Action(() =>            {                if (Text.Length > 2000)                {                    Text = "";                }                AppendText($"{DateTime.Now.ToString("MM-dd HH:mm:ss ffff")} {msg} {Environment.NewLine}");            }));        }        else        {            if (Text.Length > 2000)            {                Text = "";            }            AppendText($"{DateTime.Now.ToString("MM-dd HH:mm:ss ffff")} {msg} {Environment.NewLine}");        }    }    public void RefreshRichText(string msg)    {        queueServer.Enqueue(msg);    }}

其中有一个地方要注意的是

Refresh方法中,当出现主线程访问InvokeRequired = false;执行下面的这种刷新方法,当控件被使用在子线程中时,InvokeRequired = true;这样就能保证在两种情况下都可以正常使用,否则任然会导致界面卡死。

页面设计

页面设计比较简单,主要实现数据展现和右键清空。

最后页面调用:

经过上诉处理后,调用方法也比较简单:只需要将控件拖到指定的页面,然后使用控件的方法myRichTextBox1.RefreshRichText($" 第{info.Number}个,耗时{st.ElapsedMilliseconds} 毫秒");就可以疯狂的刷新页面,尤其在进行监控执行过程,显示处理日志流水时就可以很方便的使用。也便于在跟多的页面集成使用。当然使用队列的好处就是,保证执行顺序的先后关系,方便排查问题。不然高频率刷新,容易覆盖数据。

好啦,如果对你有帮助的话,你也可以试试。有其他更有意思的处理方法,也可以留言互相交流。

标签: #执行刷新操作时线程出现异常