2018/6/4~2018/6/8 周记
一转眼一周时间已经过去,这一周的任务是做一个实时更新的窗体运用,项目的要求有如下三点:
1、界面上窗口号不能写死,要可配置的。
2、设置一个定时器,每隔10秒更新数据。
3、由于有五个窗口,所以要使用五个DataGridView控键,但是更新数据时要求只能访问一次数据库,以此来提高性能。
这个项目逻辑很简单,可以说没有逻辑,就是去数据库取到数据然后定时更新到界面上,本来想着给个Demo的话,马上就能照着Demo写出来,但是主管说这次不给Demo,要我自己写出来,刚听的时候还有点心里没底。毕竟这个项目是要拿出去用的,所以有点慌。后来主管又说他已经做好了,这个就相当于给我练手用的,所以必须用三层来写。一听已经做完,只是拿来练手的,心理压力马上就小了好多好多。而且不懂的还可以问主管。
首先第一个,界面上窗口号不能写死,要可配置的。实现这个很简单,对比将数据库信息存放在配置文件里面,我也直接将窗口号信息直接写在配置文件里面,将数据读出来并赋值给lable就行了。实现代码如下所示:
lblRoomName1.Text = ConfigurationManager.AppSettings["0001"]; lblRoomName2.Text = ConfigurationManager.AppSettings["0002"]; lblRoomName3.Text = ConfigurationManager.AppSettings["0003"]; lblRoomName4.Text = ConfigurationManager.AppSettings["0004"]; lblRoomName5.Text = ConfigurationManager.AppSettings["0005"];
后面主管说要我通过数据库表里的数据将值赋值给lable,虽然取到需要的表,表里面的数据也有,但是不知道如何将表数据准确赋值给lable,主管实际操作一波,使用DataView来实现,因为DataView里面有可以筛选表数据的方法RowFilter(),DataView就是视图的意思,可以虚拟出一张表并获取真实表的数据,和SQL里面视图一样的道理,对DataView操作就是对表进行操作。代码如下:
//通过读取数据库数据更新科室名称 DataTable dt = bllXtRoom.GetList(); //创建一个视图,虚拟表数据 DataView dv = dt.DefaultView; //通过视图筛选符合条件的数据 dv.RowFilter = "RoomCode ='001' "; //赋值 lblRoomName1.Text = dv[0][1].ToString(); dv.RowFilter = "RoomCode ='002' "; lblRoomName2.Text = dv[0][1].ToString(); dv.RowFilter = "RoomCode ='003' "; lblRoomName3.Text = dv[0][1].ToString(); dv.RowFilter = "RoomCode ='004' "; lblRoomName4.Text = dv[0][1].ToString(); dv.RowFilter = "RoomCode ='005' "; lblRoomName5.Text = dv[0][1].ToString();
将表数据根据条件分别填入五个DataGridView里面。我的做法就是写五条数据库语言,分别查出所需要的数据,然后分别填入DataGridView里面(后面要一次性跟新整个界面数据时,这样取数据是不行的!每跟新一次数据就要访问五次数据库!)数据填入DataGriView里面并不美观,其中最重要的是数据在DataGridView里面自适应列宽。这样数据看着才会比较整齐!因为背景图片已经给出来了,所以每个DataGridView的大小已经定下来了。DataGridView里面每一列的宽度就要自适应,不然很影响美观的。自适应代码如下所示:
public void SetWidth(DataGridView data) { int width = 0; //对于DataGridView的每一个列都调整 for (int i = 0; i < data.Columns.Count; i++) { //将每一列都调整为自动适应模式 data.AutoResizeColumn(i, DataGridViewAutoSizeColumnMode.AllCells); //记录整个DataGridView的宽度 width += data.Columns[i].Width; } //判断调整后的宽度与原来设定的宽度的关系,如果是调整后的宽度大于原来设定的宽度, //则将DataGridView的列自动调整模式设置为显示的列即可, //如果是小于原来设定的宽度,将模式改为填充。 if (width > data.Size.Width) { data.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells; } else { data.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill; } //冻结某列 从左开始 0,1,2 data.Columns[1].Frozen = true; }
数据填入DataGridView后就是定时更新的问题了,定时更新有两个方法,一个是写一个线程,通过线程定时来定时访问数据库实现更新数据,第二个是使用定时器,写一个定时器来定时执行。简单线程很简单,只需要实例化一个Thread,然后调star()方法。代码如下:
private void UpData() { while (true) { //运行时间 Thread.Sleep(10000); DataTable dt = bllQueueList.GetTable(); // dataGridView4.DataSource = dt4; SetDT(dt); //qubiaotou(dataGridView4); //SetWidth(dataGridView4); } } //使用线程调用方法 //在Load方法里面执行 Thread th = new Thread(UpData); th.Start();
定时器的话也很简单,拉一个定时器控键,设置Enabled=true,Interval=1000;//执行时间间隔,单位为毫秒
//方法二:使用定时器 System.Timers.Timer timer = new System.Timers.Timer(); timer.Enabled = true; timer.Interval = 10000;//执行间隔时间,单位为毫秒 timer.Start(); timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer1_Elapsed); private void Timer1_Elapsed(object sender, ElapsedEventArgs e) { DataTable dt = bllQueueList.GetTable(); SetDT(dt); }
但是这样写出来的定时器还是会报错,错误信息是“线程间操作无效: 从不是创建控件“”的线程访问它”。解决方法是通过写一个委托来执行
private delegate void SetDtCallback(DataTable dt); private void SetDT(DataTable dt) { // InvokeRequired需要比较调用线程ID和创建线程ID // 如果它们不相同则返回true if (this.InvokeRequired) { SetDtCallback d = new SetDtCallback(SetDT); this.Invoke(d, new object[] { dt }); } else { // dataGridView4.DataSource = dt; ShowData(); } }
虽然功能实现了,但是还是不懂什么意思。。
将一个表里面数据通过条件分成多个表:
DataTable dt = bllQueueList.GetTable(); DataView dataview = dt.DefaultView; DataTable dt1 = new DataTable(); //通过视图筛选符合条件的数据 dataview.RowFilter = "Window='1001'"; //创建一个新的表,该表只显示"Queueno","Name"这两个列的值并把表数据赋值给表dtTemporary, //true:不显示相同的数据,false:显示全部数据 dt1 = dataview.ToTable(true, "Queueno", "Name"); dataGridView1.DataSource = dt1; qubiaotou(dataGridView1); SetWidth(dataGridView1);
还有一些细节方面的问题。。用户体验真的很重要!!!
操作数据库时,往表里添加数据时报将截断字符串或二进制数据。的错误。原因是数据的长度不符合才造成的。只要把数据长度增加就行了!!