在后台WPF中更新列表框

时间:2012-11-02 20:35:31

标签: c# wpf multithreading listbox backgroundworker

我正在尝试创建一个类似超级终端的程序,但我无法获得串行端口以获取一行并将其发布到后台的列表框中。在下面的例子中,它将冻结整个程序,而for循环运行100次,然后吐出所有100行......我希望它逐行更新,我不知道它为什么这样做。

我也试过背景工作者,但似乎做了同样的事情。

提前致谢...

    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);
        }

    }

3 个答案:

答案 0 :(得分:1)

您正在UI线程中运行SP.ReadLine代码。

我已将您的代码拆分为三种方法,而不是一大堆代码。

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);
    }
}

在这个澄清版本中,有三种方法

  1. Kickoff ,创建并运行新主题
  2. 计划工作,在_thread上运行并计划填写
  3. 填充,实际执行您打算在_thread上运行的工作
  4. 问题是 Kickoff 在UI线程上运行, ScheduleWork _thread上运行,而 Fill 在UI上运行线。

    Dispatcher.BeginInvoke本质上意味着“采用这种方法,并在你想要安排它时,在UI线程上运行它,kthxbai。”所以你的代码都在UI线程上运行

    您需要执行以下操作

    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);
        }
    }
    

答案 1 :(得分:0)

我认为正在发生的事情是你的线程优先于GUI线程。您必须睡眠线程,以便GUI可以更新,或者它只会排队一堆更新,然后在事件结束且程序空闲时处理该队列。将它设置为较低的优先级可能不是一个很好的方法。

就个人而言,我会将COM端口逻辑移动到一个对象中,并将其工作在自己的线程上。然后,您可以在计时器上轮询该对象的属性,以查看是否有任何数据可供读取。

答案 2 :(得分:0)

您无法从后台线程更新UI。尝试将此行更改为

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

尝试使用MSDN: DispatcherPriority来改变线程的优先级。