1

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

我也尝试过 backgroundworker 但它似乎做了同样的事情。

提前致谢...

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

    }
4

3 回答 3

1

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

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

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. ScheduleWork,它运行_thread并安排填充
  3. Fill,它实际上执行您打算运行的工作_thread

问题是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);
    }
}
于 2012-11-02T21:09:16.873 回答
0

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

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

于 2012-11-02T20:40:47.870 回答
0

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

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

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

于 2012-11-02T21:03:18.100 回答