8

我是一名技术级别的员工,帮助在制造测试环境中进行一些编码。具体问题是在 C# 中处理事件。不仅仅是 Button_click,特别是如果我有来自串行端口的数据流并且必须根据通过串行端口传入的内容实时更新 UI。例如,如果我有两种最终都做同样事情的方法,那么它们之间有什么区别:

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) {
    input = (sender as SerialPort).ReadLine();
    if (input.Contains("look for this"))
        this.Invoke(new EventHandler(doSomething));
}

和类似的东西:

void OnGotData(object sender, EventArgs e) {...};
delegate void UpdateCallback(data d);
void doSomething(data d) {
   ...
  if (field.InvokeRequired) {
            UpdateCallback x = doSomething;
            this.Invoke(x, new object[] { d });
  }
  else {
            field.Text = d;
  }
   ...
}

有哪些权衡?更复杂的第二种方法是惯例问题吗?当实时性能很重要时,我可以在任何地方使用第一种方法吗?

4

1 回答 1

1

如果我理解:第一种方法 - 总是调用调用来更新 UI 第二种方法 - 如果 InvokeRequired 返回 true 调用调用 else - 只是做 UI 的东西

现在,如果我们知道创建了控制句柄,并且我们只想进行小而快速的 UI 更新,我们可以使用第一种方法,并且 UI 将负责,但使用 Invoke 死锁仍然是可能的。如果我们现在不创建控制句柄,我们必须调用 IsHandleCreated 以确保 Invoke 成功并且不会引发异常。如果 IsHandleCreated 返回 false,我们将无法通过 Invoke 进行更新,我们必须等待句柄被创建。

第二种方法更糟糕,因为 field.InvokeRequired 可能会在未创建控件句柄的情况下返回 false,并且当我们调用field.Text = d;控件的句柄时,可能会在后台线程上创建控件,从而将控件隔离在没有消息泵的线程上并使应用程序不稳定。

所以对我来说这是更好的方法:

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) {
    input = (sender as SerialPort).ReadLine();
    if (input.Contains("look for this"))
    {   if (this.IsHandleCreated == false)
        {
        //do some stuff to proper handle creation or just wait for handle creation
        }

        this.BeginInvoke(new EventHandler(doSomething));
    }
}
于 2013-07-23T12:54:31.657 回答