线程化和更新 GUI

Threading and updating the GUI

我一直在开发一个 WinForms 实用程序,它从文本文件中获取命令 and/or 数据,并根据该文件的内容通过串行传输或请求更多数据。这一切都很完美,但我正在努力研究如何让 GUI 提供一些正在发生的事情的反馈。在其当前结构中,主窗体加载并且 Load() 事件打开文本文件并处理其内容

tp = new TProcess();
tp.FileOpen();

TProcess 和所有其他涉及通过串口通信的 类 被收集到一个编译为 DLL 的子项目中。反过来,TProcess 将创建我的 SerialDevice 对象的一个​​新实例(也在我的 DLL 中定义)并将我的数据传递给它,然后告诉它如何处理它,例如

//TProcess


if (File.Exists(filey))
            try
                {

                StreamReader file = new StreamReader(@"filey");



                List<clsStuff> stuffList = new List<clsStuff>();

                while ((line = file.ReadLine()) != null)
                    {
                    //process and add to list
                    }

                    var SD = new SerialDevice();
                    SD.List = stuffList;                        
                    SD.Send();

                file.Close();

                }
            catch (Exception e)
                {
              //Write Error File

                }

        }

我的 SD Class 定义所有端口参数,发送第一个项目数据包并使用 DataReceived 事件从远程设备接收确认数据包,然后一次发送列表中的项目,直到它已经完成并退出。 因此,我的问题(抱歉啰嗦)是我如何传递某种反馈(可能是每次我收到数据包确认时收到的像 Record X 这样的字符串),因为 GUI 线程没有创建我的 SD例如,如果这是一个更紧凑的程序,并且 GUI 线程调用了 SD,我会使用委托和 BeginInvoke,但我看不出我如何在这里做到这一点,因为 GUI 对 SD 实例一无所知,同样 SD 对 SD 实例一无所知图形用户界面。我觉得这可能可以通过 SynchronisationContext 解决,但我不知道如何实现它。

         public void Send()
                {
                if (!serialP.IsOpen)
                    {
                    PortOpen();
                    serialP.ReceivedBytesThreshold = 4;
                    }
                serialP.Write(CurrentListItem, 0, 11);


                }
      private void serialP_DataEvent(object sender, SerialDataReceivedEventArgs e)// This triggers when the response is received
                {


                        byte[] Ack = new byte[4];
                        serialP.Read(Ack, 0, 4);
                        //snip of course I check these 4 bytes etc here
                                CurrentListItem++;
                                //UPDATE THE GUI BUT HOW?
                                Send()!;//next
                  }

向您的 TProcess class 添加您的 UI 可以订阅的活动:

public event EventHandler DataRecieved;

然后在您的 serialP_DataEvent 中,您可以在适当的时候执行:

if (DataRecieved != null)
{
    DataRecieved(this,EventArgs.Empty);
}

您的 UI 可以订阅这个:

tp.DataRecieved += (o,e) => { // do something to the UI };

一些注意事项:

1) 如果使用通用 EventHandler<T> 而不是 EventHandler,则可以在事件中传递信息。其中 T 是您要发送的任何数据的 class

2) 看起来 FileOpen 是同步和阻塞的,所以它会阻止您的 UI 更新。使其异步或至少使用 Task.Run

3) 如果使其异步,则可能会遇到尝试从非 UI 线程更新 UI 的问题。您将需要使用 Invoke 将 UI 更新推回到 UI 线程(您不会说这是 WinForms 还是 WPF,但它们是相似的)。