线程化和更新GUI

时间:2016-06-21 14:47:30

标签: c# user-interface serial-port thread-synchronization

我一直在研究WinForms实用程序,该实用程序从文本文件中获取命令和/或数据,并根据此文件的内容通过串行传输或请求更多数据。这一切都很完美,但我正在努力研究如何让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类定义所有端口参数,发送第一个项目数据包并使用DataReceived事件从远程设备接收确认数据包,然后一次一个地从列表中发送项目,直到它完成并退出。 因此,我的问题(抱歉长篇大论)是我如何传递某种反馈(也许像每次收到数据包确认时收到的记录X之类的字符串),因为GUI线程没有创建我的SD,所以GUI正在发生例如,如果这是一个更紧凑的程序并且GUI线程已经调用SD我将使用委托和BeginInvoke但我不知道我怎么能在这里做,因为GUI对SD实例一无所知,同样SD对此一无所知GUI。我觉得这可以通过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
                  }

1 个答案:

答案 0 :(得分:0)

向您的TProcess班级添加您的用户界面可订阅的活动:

public event EventHandler DataRecieved;

然后在serialP_DataEvent你可以,在适当的时候做:

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

然后您的用户界面可以订阅:

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

几点说明:

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

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

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