简体   繁体   English

在后台WPF中更新列表框

[英]Updating Listbox in the background WPF

I am trying to make a hyper-terminal like program and i am having trouble getting the serial port to get a line and post it in the list box in the background. 我正在尝试制作一个像程序一样的超级终端,但我在获取串行端口以获取线路并将其发布到后台的列表框中时遇到了麻烦。 In the example below it will freeze the whole program while the the for loop runs 100 times and then spit out all 100 lines... i want it to update line by line and i am not sure why its doing it. 在下面的示例中,它将使整个程序冻结,而for循环将运行100次,然后吐出全部100行...我希望它逐行更新,但我不确定为什么这样做。

I also tried backgroundworker but it seemed to do the same thing. 我也尝试了backgroundworker,但它似乎做同样的事情。

Thanks in advance... 提前致谢...

    static System.Threading.Thread thread;
    public void button2_Click(object sender, RoutedEventArgs e)
    {
        if(Sp.IsOpen){
            stop = false;

            thread = new System.Threading.Thread(
                new System.Threading.ThreadStart(
                  delegate()
                  {
                    System.Windows.Threading.DispatcherOperation
                      dispatcherOp = listBox1.Dispatcher.BeginInvoke(
                      System.Windows.Threading.DispatcherPriority.Normal,
                      new Action(
                        delegate()
                        {
                            for(int y = 0; y <100; y++)
                            {
                                String line = Sp.ReadLine();
                                listBox1.Items.Add(line);
                            }
                        }
                               ));

              }
          ));
            thread.Start();


        }else{
            item.Content = ("No Comm Ports are Open");
            item.IsSelected = true;
            listBox1.Items.Add(item);
        }

    }

You are running your SP.ReadLine code in the UI thread. 您正在UI线程中运行SP.ReadLine代码。

I've split your code into three methods instead of one big splat of code. 我将您的代码分为三种方法,而不是一小段代码。

private Thread _thread;

private void Kickoff()
{
    _thread = new Thread(() => ScheduleWork(listBox1));
    thread.Start();
}

private void ScheduleWork(ListBox box)
{
    box.Dispatcher.BeginInvoke((Action)() => Fill(box));
}

private void Fill(ListBox box)
{                           
    for(int y = 0; y <100; y++)
    {
        String line = Sp.ReadLine();
        listBox1.Items.Add(line);
    }
}

In this clarified version, there are three methods 在此澄清的版本中,有三种方法

  1. Kickoff , which creates and runs the new thread 启动 ,创建并运行新线程
  2. ScheduleWork , which runs on _thread and schedules filling ScheduleWork ,它在_thread上运行并计划填充
  3. Fill , which actually performs the work you intended to run on _thread Fill ,实际上执行您打算在_thread上运行的工作

The problem is that Kickoff runs on the UI thread, ScheduleWork runs on _thread , and Fill runs on the UI thread. 问题在于, 启动程序在UI线程上运行, ScheduleWork_thread_thread ,而Fill在UI线程上运行。

Dispatcher.BeginInvoke essentially means "take this method and run it on the UI thread whenever you feel like scheduling it, kthxbai." Dispatcher.BeginInvoke本质上是指“采用这种方法并在需要调度时在UI线程上运行它,kthxbai。” So your code all runs on the UI thread . 因此,您的代码全部在UI线程上运行

You need to do something like the following 您需要执行以下操作

private Thread _thread;

private void Kickoff()
{
    _thread = new Thread(() => ScheduleWork(listBox1));
    thread.Start();
}

private void ScheduleWork(ListBox box)
{                  
    for(int y = 0; y <100; y++)
    {
        String line = Sp.ReadLine();
        box.Dispatcher.BeginInvoke((Action<string>)(str) => 
            listBox1.Items.Add(str),
            line);
    }
}

I think what's going on is that your thread is taking priority over the GUI thread. 我认为这是因为您的线程的优先级高于GUI线程。 You have to sleep the thread so the GUI can update or it will just queue up a bunch of updates and then process that queue when the event is over and the program sits idle. 您必须休眠线程,以便GUI可以更新,否则它将只是排队进行一系列更新,然后在事件结束且程序处于空闲状态时处理该队列。 Setting it to a lower priority probably isn't a great way to do it. 将其设置为较低的优先级可能不是一个好方法。

Personally, I would move the COM port logic into an object and have that work on its own thread. 就个人而言,我会将COM端口逻辑移到一个对象中,并在其自己的线程上进行工作。 Then you could poll that object's properties on a timer to see if any data was ready to be read. 然后,您可以在计时器上轮询该对象的属性,以查看是否已准备好读取任何数据。

You cannot update the UI from a background thread. 您不能从后台线程更新UI。 Try changing the line dowing this to 尝试将行修改为

listBox1.Dispatcher.BeginInvoke(DispatcherPriority.Render, ()=>listBox1.Items.Add(line));

try playing with the MSDN: DispatcherPriority to change the priority of your thread. 尝试使用MSDN:DispatcherPriority更改线程的优先级。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM