C# 在wpf中使用滚动结束功能加快对texbox的写入速度?

C# 在wpf中使用滚动结束功能加快对texbox的写入速度?,c#,wpf,multithreading,textbox,event-handling,C#,Wpf,Multithreading,Textbox,Event Handling,我一直在寻找一种在C#/WPF中尽可能快地更新多行文本框的方法。所以我想我会和你们核实一下,看看你们是否能给我一些建议/提示或帮助 我想要的是能够输出尽可能多的数据尽可能快的多行文本框与滚动结束时更新,数据来自串行连接。我用C#/Forms完成了这项工作,没有任何问题。但在WPF中,这并不是那么容易 因此,如果我只写一行文本框,那么5000个项目需要940毫秒。 但对于多线,它需要143秒。 如果我没有滚动到文本框的末尾,那么同样的数据需要112秒 代码创建一个带有队列的类实例,用5000个项目

我一直在寻找一种在C#/WPF中尽可能快地更新多行文本框的方法。所以我想我会和你们核实一下,看看你们是否能给我一些建议/提示或帮助

我想要的是能够输出尽可能多的数据尽可能快的多行文本框与滚动结束时更新,数据来自串行连接。我用C#/Forms完成了这项工作,没有任何问题。但在WPF中,这并不是那么容易

因此,如果我只写一行文本框,那么5000个项目需要940毫秒。 但对于多线,它需要143秒。 如果我没有滚动到文本框的末尾,那么同样的数据需要112秒

代码创建一个带有队列的类实例,用5000个项目填充队列,然后尝试尽快将数据输出到UI->texbox。 我将秒表刻度添加到输出中,以便查看每个功能的计时

显示输出格式

ItemValueDQ->从开始添加到队列勾号Ev->从开始退出队列的事件勾号TB->从开始的文本框输出时间(ms)

我编写了一个小测试程序,下面的代码与项目相同,可以在这里下载->

testcase if语句位于main窗口中:TxTextAdd()

我的想法是,有一种方法可以更改事件处理,这样每次ui/事件处理程序启动时,它都可以输出尽可能多的项。所以我们可以一次打印多个项目,而不是每个事件打印一个项目? 但我不知道如何实施这一解决方案

有什么想法吗

enter 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Threading;
using System.Windows.Threading;

namespace BlockingCollectionAsFIFO
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        /// Create FIFO class
        FIFO_Class FIFOqueue = new FIFO_Class();

        // Display stopwatch
        Stopwatch DispStop = Stopwatch.StartNew();

        // Holds texbox string in one of the tests
        string TextBox_Text = "";

        public MainWindow()
        {
            InitializeComponent();

            // register UI update event to populate textbox from queue dequeue
            FIFOqueue.UI_Update += new FIFO_Class.UI_EventHandler(TxTextAdd);

            string ID = "A";

            /// Create new add thread in class
            for (int i = 0; i < 5; i++)
            {
                if(i == 1)
                {
                    ID = "B";
                }
                else if(i == 2)
                {
                    ID = "C";
                }
                else if (i == 3)
                {
                    ID = "D";
                }
                else if (i == 4)
                {
                    ID = "E";
                }
                // create thread
                FIFOqueue.CreateAddThread(ID);
            }

            /// Create new read thread in class
            FIFOqueue.CreateReadThread();
        }

        public void TxTextAdd(string Data)
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Input, new ThreadStart(() =>
            {
                try
                {
                    /// Put togheter the string that we are going to display
                    Data += " TB->" + DispStop.ElapsedMilliseconds.ToString() + "ms";

                    /// true => only update the one row texbox with the latest string
                    if(true)
                    {
                        textbox2.Text = Data;
                    }
                    else
                    {
                        /// true => add string to TextBox_Text variable and display that (scroll to end)
                        /// false => add string to TextBox control and scroll to end
                        if (true)
                        {
                            TextBox_Text += Data + System.Environment.NewLine;
                            textbox.Text = TextBox_Text;
                        }
                        else
                        {
                            textbox.Text += Data + System.Environment.NewLine;
                            textbox.ScrollToEnd();
                        }
                    }
                }
                catch
                {}
            }));

        }

        private void btn_RUN_Click(object sender, RoutedEventArgs e)
        {

        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            /// Dispose alive dequeue thread
            FIFOqueue.Dispose();
        }
    }

    class FIFO_Class
    {
        // Main Queue
        private BlockingCollection<Package> queue = new BlockingCollection<Package>(new ConcurrentQueue<Package>());

        // Events
        public delegate void UI_EventHandler(string message);
        public event UI_EventHandler UI_Update;

        private Thread DeQueueThread;

        Stopwatch stop = Stopwatch.StartNew();


        public void CreateAddThread(string ID)
        {
            Thread t = new Thread(() => Add(ID));
            t.Start();
        }


        private void Add(string ID)
        {
            /// Just add some data
            for (int i = 0; i < 1000; i++)
            {
                Package pack = new Package();
                pack.ID = ID;
                pack.Data = i;
                /// Add pack into queue
                queue.Add(pack);
            }
        }

        public void CreateReadThread()
        {
            DeQueueThread = new Thread(ProcessPackets);
            DeQueueThread.Start();
        }

        private void ProcessPackets()
        {
            string Output;

            /// the try function exist so I can use abort thread
            try
            {
                while (true)
                {
                    /// Retrive a package from queue
                    Package e = queue.Take();
                    // check if there is any data in package
                    if (e != null)
                    {
                        /// Convert data from package to string, stopwatch puts number of ticks from the time the thread was created
                        Output = e.ID + e.Data.ToString() + " DQ-> " + stop.ElapsedTicks.ToString() + " ticks";
                        /// check if we have any subscribers on UIupdate event
                        UI_Update_Process(Output);
                    }
                }
            }
            catch (ThreadAbortException)
            {
            }

        }

        public void Dispose()
        {
            // Abort Thread.
            DeQueueThread.Abort();
            // Wait for the thread to terminate.
            DeQueueThread.Join();
        }

        // UI update Handler Event process
        protected void UI_Update_Process(string Data)
        {
            if (UI_Update != null)
            {
                //UI_Update(Data);
                UI_Update(Data + " Ev->" + stop.ElapsedTicks.ToString() + "ticks");
            }
        }
    }

    class Package
    {
        public string ID;
        public int Data;
    }
}
enter
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Data;
使用System.Windows.Documents;
使用System.Windows.Input;
使用System.Windows.Media;
使用System.Windows.Media.Imaging;
使用System.Windows.Navigation;
使用System.Windows.Shapes;
使用System.Collections.Concurrent;
使用系统诊断;
使用系统线程;
使用System.Windows.Threading;
命名空间阻止集合IFO
{
/// 
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
///创建FIFO类
FIFO_类FIFOQUUE=新的FIFO_类();
//显示秒表
Stopwatch DispStop=Stopwatch.StartNew();
//在其中一个测试中保存texbox字符串
字符串TextBox_Text=“”;
公共主窗口()
{
初始化组件();
//注册UI更新事件以从队列出列填充文本框
FIFOqueue.UI_Update+=新的FIFO_类.UI_事件处理程序(TxTextAdd);
字符串ID=“A”;
///在类中创建新的添加线程
对于(int i=0;i<5;i++)
{
如果(i==1)
{
ID=“B”;
}
else如果(i==2)
{
ID=“C”;
}
else如果(i==3)
{
ID=“D”;
}
else如果(i==4)
{
ID=“E”;
}
//创建线程
FIFOqueue.CreateAddThread(ID);
}
///在类中创建新的读取线程
CreateReadThread();
}
public void TxTextAdd(字符串数据)
{
Dispatcher.BeginInvoke(DispatcherPriority.Input,新线程开始(()=>
{
尝试
{
///把我们要显示的字符串放在一起
数据+=“TB->”+DispStop.elapsedmillisons.ToString()+“ms”;
///true=>仅使用最新字符串更新单行文本框
如果(真)
{
textbox2.Text=数据;
}
其他的
{
///true=>将字符串添加到TextBox_文本变量并显示(滚动到末尾)
///false=>将字符串添加到TextBox控件并滚动到末尾
如果(真)
{
TextBox_Text+=Data+System.Environment.NewLine;
Text=textbox\u Text;
}
其他的
{
textbox.Text+=Data+System.Environment.NewLine;
textbox.ScrollToEnd();
}
}
}
抓住
{}
}));
}
私有无效btn\u运行\u单击(对象发送者,路由目标e)
{
}
私有无效窗口\u关闭(对象发送方,System.ComponentModel.CancelEventArgs e)
{
///处理活动的出列线程
FIFOqueue.Dispose();
}
}
先进先出类
{
//主队列
private BlockingCollection queue=new BlockingCollection(new ConcurrentQueue());
//事件
公共委托无效UI_事件处理程序(字符串消息);
公共事件UI\u事件处理程序UI\u更新;
私有线程退出队列线程;
秒表停止=Stopwatch.StartNew();
public void CreateAddThread(字符串ID)
{
线程t=新线程(()=>Add(ID));
t、 Start();
}
私有无效添加(字符串ID)
{
///只需添加一些数据
对于(int i=0;i<1000;i++)
{
软件包=新软件包();
pack.ID=ID;
包装数据=i;
///将包添加到队列中
队列。添加(包);
}