惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LINUX DO - 最新话题
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
PCI Perspectives
PCI Perspectives
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
H
Heimdal Security Blog
S
Security @ Cisco Blogs
N
News | PayPal Newsroom
J
Java Code Geeks
罗磊的独立博客
Security Archives - TechRepublic
Security Archives - TechRepublic
N
News and Events Feed by Topic
V
V2EX
WordPress大学
WordPress大学
Google Online Security Blog
Google Online Security Blog
N
News and Events Feed by Topic
www.infosecurity-magazine.com
www.infosecurity-magazine.com
月光博客
月光博客
AI
AI
小众软件
小众软件
The GitHub Blog
The GitHub Blog
MongoDB | Blog
MongoDB | Blog
A
Arctic Wolf
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
美团技术团队
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
Tailwind CSS Blog
S
Schneier on Security
博客园 - 三生石上(FineUI控件)
F
Full Disclosure
B
Blog RSS Feed
Forbes - Security
Forbes - Security
S
SegmentFault 最新的问题
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
人人都是产品经理
人人都是产品经理
云风的 BLOG
云风的 BLOG
Jina AI
Jina AI
Cisco Talos Blog
Cisco Talos Blog
U
Unit 42
Project Zero
Project Zero
H
Hacker News: Front Page
Y
Y Combinator Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
The Cloudflare Blog
大猫的无限游戏
大猫的无限游戏
S
Secure Thoughts
The Hacker News
The Hacker News
Microsoft Azure Blog
Microsoft Azure Blog

博客园 - lichdr

高德地图热力图的Flutter实现 App消息推送的简单实现 nginx访问日志过滤(多条件) CAS的service参数验证 自定义Token的CAS登录 单元格的计算 表格行列的删除 表格行列的移动 FastReport的一些另类用法 FastReport分组页码 RFID会议签到系统总结(二十二)――系统中的模式 RFID会议签到系统总结(二十一)――服务端的通讯 RFID会议签到系统总结(二十)――数据窗体状态控制 RFID会议签到系统总结(十八)――菜单与工具栏的加载 RFID会议签到系统总结(十七)――菜单与工具栏的改造(下) RFID会议签到系统总结(十六)――菜单与工具栏按钮的改造(上) RFID会议签到系统总结(十五)――管控端的窗体组织 RFID会议签到系统总结(十四)――管控端业务模块的加载 RFID会议签到系统总结(十三)――模块概述(下)
RFID会议签到系统总结(十九)――单数据窗体
lichdr · 2007-07-25 · via 博客园 - lichdr

所谓的单数据窗体是指那种在窗体只显示一张单表的数据的窗体,主要就是用于显示基本表,因为这个系统要显示的差不多就是基本表为主,这一篇主要讲这个数据显示窗体的基类。

既然是基类嘛,当然要提供一些虚方法给子类来改写,要有一些变量必须由子量来初始化。首先必须由子量来提供实例的变量主要是跟子类关联的数据表有关,因为窗体的始化及UI的呈现都是与数据有关的,所以上述变量的初始化必须是在构造函数的最开始的地方进行。

       public frmData()

       {

           InitVariable();

           if (!LoadData())

              return;

           InitializeComponent();

           toolBar1.ButtonClick += new ToolBarButtonClickEventHandler(toolBar1_ButtonClick);

       }

       /// <summary>

       /// 初始化一些由子类提供的变量

       /// </summary>

       protected virtual void InitVariable()

        {

       }

       /// <summary>

       /// 加载数据

       /// </summary>

       /// <returns></returns>

       protected virtual bool LoadData()

       {

           try

           {

              if (stMgr != null && stMgr.LastState == StateEnum.Insert) //新增一笔记录后要清除以前查询条件,否则会看不到新增的那一笔记录

                  condition.ClearCondition();

              DBCommandWrapper command = condition.BuildCondidtionCommand();

              dataTable = recordAction.GetAll(command);

              if (dataTable.Rows.Count == 0)

                  Msg.ShowInformation("没有可显示的记录");

              return true;

           }

           catch(Exception)

           {

              return true;

           }

       }

在子窗体的InitVariable方法里,根据当前窗体关联的数据表初始化对应的变量,这里其实主要就是初始化数据对象及跟它有关的一些东西(比如表示查询条件的类等等),比如“会议基本表”这个窗体

       protected override void InitVariable()

       {

           record = new MeetInfoBO();

           recordAction = new MeetInfoBO();

           condition = recordAction.GetQueryCondition();

       }

上面的recordrecordAction是数据对象的基类,为什么要提供呢?因为考虑到数据显示与数据操作的问题。虽说是基本表,但有些还是有外键关联的,数据显示的时候我们并不是直接从表本身上取数据,一般会从这个表衍生的视图上取数据(可以提供外键的友好显示)。而新增、修改的时候,操作的还是那个基本表,所以分了二个数据对象(这里的会议表没什么外键,所以二者是一致的)。

缺省情况下,数据窗体是从数据表里取出所有的数据,当然在子窗体里可以根据不同情况来取,也可以根据条件排序。

数据窗体最为繁琐的地方就是工具栏,数据窗体的工具栏一般就是一些导航及数据操作按钮,但.Net Framework带的这个ToolBar实在做得是不算好。虽然上几篇化了点功夫改造了一下,但这里的工具栏是要在设计期用的,要在ToolBar的设计器中加入自定义类型的ToolBarButton要费点力气,想想就算了,反正用原始的工具栏也能解决问题,虽然看起来比较难看点。

先来看一下ToolBarButtonClick事件:

       protected virtual void toolBar1_ButtonClick(object sender, ToolBarButtonClickEventArgs e)

       {

           currPos = curM.Position;

           switch(e.Button.ToolTipText)

           {

              case "First":

                  grid.UnSelect(curM.Position);

                  curM.Position = 0;

                  grid.Select(curM.Position);

                  break;

              case "Previous":

                  grid.UnSelect(curM.Position);

                  curM.Position = (curM.Position == 0) ? 0 : curM.Position - 1;

                  grid.Select(curM.Position);

                  break;

              。。。。。。

              。。。。。。

              case "Add":

                  stMgr.SetInsert();

                  grid.Enabled = false;

                  BeforeInsert();

                  break;

              。。。。。。

              。。。。。。

              case "OK":

                  if (!BeforePost()) return;

                  if (stMgr.CurrentState != StateEnum.Query)

                     stMgr.btnOKClick();

                  else

                     CombineCondition();

                  switch (stMgr.CurrentState)

                  {

                     case StateEnum.Insert:

                         AfterInsert();

                         break;

                     case StateEnum.Edit:

                         AfterEdit();

                         break;

                     case StateEnum.Query:

                         AfterQuery();

                         break;

                  }

                  LoadData();

                  grid.Enabled = true;

                  ReBind();

                  stMgr.SetBrowse();

                  grid.Refresh();

                  grid.Focus();

                  if (curM.Count > 0)

                  {

                     switch (stMgr.LastState)

                     {

                         case StateEnum.Insert:

                            currPos = curM.Count - 1;

                            break;

                         case StateEnum.Query:

                            currPos = 0;

                            break;

                     }

                     currPos = (currPos >= curM.Count) ? curM.Count - 1 : currPos;

                     grid.UnSelect(curM.Position);

                     grid.Select(currPos);

                     curM.Position = currPos;

                  }

                  break;

              。。。。。。

              。。。。。。

           }

       }

上面这个方法为什么要声明成virtual呢?这是为了让子窗体可以有机会改写而做一些自己的事情,其实最后在子窗体中也没做什么大的事情,只是重新初始化了一下record这个变量,这个步骤比较好的方法本应该是在方法的入口处放一个Place Holder来让子窗体写,不过因为最开始时这么写,后来就没改了。

第二个要说的地方就是那个switch后面跟的条件了,找来找去实在找不出什么属性可以用来分清工具栏的各个按钮,用index之类的属性显然是不合适的,而Tag我已经有新的用途了,最后选了个ToolTipText属性,好歹也是个字符串的属性,看代码也还算看得明白。

上面当然是省略了很多的分支,不过处理都是大同小异的,所以就不一一列出来了。主要的技巧是放了大量的Place Holder,主要是那些After***Before***方法,其实那些方法在基类里基本是空的虚方法,即使有点代码也就二三行,这些方法主要用途就是开放接口让子窗体能够做一些特殊处理。

那工具栏状态是如何控制的,及数据操作(新增、修改、删除、查询)是如何进行的呢,从上面看不出来,其实所有的奥秘都在stMgr状态管理器里,不过这个篇幅比较长,要放在下篇讲了。

最后记一个不太扣这一篇主旨的东西――点击grid选择整行,这是从网上查来的。其实其他的东西当然也有很多是从网上来的,但那些东西都比较大,要经过消化,这个小东西没什么可消化的,直接在这里记一笔了。

gridMouseUp事件里写:

       private void grid_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)

       {

           System.Drawing.Point pt = new Point(e.X, e.Y);

           DataGrid.HitTestInfo hti = grid.HitTest(pt);

           if(hti.Type == DataGrid.HitTestType.Cell)

           {

              grid.CurrentCell = new DataGridCell(hti.Row, hti.Column);

              grid.Select(hti.Row);

           }

       }