首先,不得不说因为助教给的这个代码的问题,实在是不好做界面……我们的思路就是用界面尽可能地展现出调度的过程并显示出最终的结果,这个结果其实包括两方面,平均时间是必须的,还有就是最终的状态,这个对比起初始信息的状态还是可以看出一定的效果的;另外,由于测试数据包含3个时间段,设计一个可以让使用者自由选定模拟数据的功能会更加人性化一点~
我们这次的UI界面效果其实并没有做的那么大,因为程序本身就是基于C#控制台的程序,在此基础上如果要搞头换面会很麻烦(为了想得到实时的数据,我们埋头读代码读了好长时间,最后助教的这套代码让我彻底crash了,好吧~),于是我们就在项目方案的空间内加入了Windows Form 界面组建并进行了简单的设计和优化(如下图所示)
首先是 UiForm 的界面:
这个界面的功能是让使用者自行选择要打开的数据信息文件,即为命令行确定要加载的电梯和乘客的信息的文件地址,然后把地址传给命令行参数,具体的界面简单效果如下图所示~
界面很简单明了,所以我们接下来还是来看代码吧,首先是按钮控制,这个其实很简单,控制打开文件的浏览界面以及关闭界面等,如下:
这里要注意的有两点:第一是我们把所有原先在空间 World -> Program.cs 里的代码全部复制到了 UiForm.cs 里,所以在资源管理器中的 Program.cs 文件中其实仅仅存在命名空间和空间引用,而真正的代码都在这个文件里;其次,由于我们的需求是在关闭这个界面以后把打开文件的文件名信息传给命令行,而这样就需要保留信息,所以这里用了 Close() 而不是 Dispose() 或者 Application.Exit() 函数~
接下来是在原先的 Program.cs 的代码中修改的部分:
新建界面并运行界面,这里用 Application.Run 可以让运行的界面保持信息循环,即暂时关闭后台控制台的执行,等关闭后再继续执行;
这里是启用了另一个界面 UiFormResult,即功能仅仅是为了显示结果的,其中 Result 是结果时间的字符串信息,由于这个数据要在新建的界面的组件中被使用,所有根据我们在网上查的资料(即注释内容),我们需要设置其数据格式类型(如下图)
而在另一个显示结果的界面里,加载界面时即要显示结果信息,其代码如下:
这样我们完整运行时的效果即是,当用户选择两个 xml 文件的路径后点击“开始执行调度”,然后转到控制台执行算法过程,最后显示结果的界面弹出,单击“退出程序”后退出~
遇到的问题:
好像是因为助教给的代码的命令行程序是多线程的,所以在开界面的时候(具体应该是执行打开文件对话框的时候)会提示错误,所以根据MSDN上的解释和改进方案,再次贴出改进方法:
/* * 单元是进程内部具有相同线程访问要求的对象的逻辑容器 * 同一单元中的所有对象都可以接收从该单元中的任何线程发出的调用 * .NET Framework 不使用单元,托管对象自己负责以线程安全的方式使用所有共享资源 * 由于 COM 类使用单元,因此公共语言运行库需要在 COM Interop 的情况下调用 COM 对象时创建并初始化一个单元 * 托管线程可以创建并进入只允许有一个线程的单线程单元 (STA)或者包含一个或多个线程的多线程单元(MTA) * 通过将线程的 ApartmentState 属性设置为 ApartmentState 枚举值之一,可以控制所创建的单元的类型 * 由于给定线程只能初始化 COM 单元一次,因此在第一次调用非托管代码之后就不能更改单元类型 * * 成员定义: * STA:Thread 将创建并进入一个单线程单元。 * MTA:Thread 将创建并进入一个多线程单元 * Unknown:尚未设置 ApartmentState 属性。 * * 解决办法两种: * * (1) * 在Main入口添加STAThread的Attribute * [STAThread] static void Main() * * (2) * Thread app = new Thread(new ParameterizedThreadStart(ShowWindow)); * app.ApartmentState = ApartmentState.STA; * 或 * Thread newThread = new Thread(new ThreadStart(ThreadMethod)); * newThread.SetApartmentState(ApartmentState.MTA); */
最后根据要求附上部分代码(仅是空间 World 的代码)