zoukankan      html  css  js  c++  java
  • 知识管理系统Data Solution研发日记之六 窗体设计器

    知识管理系统Data Solution已经有五篇文章对它进行介绍,可以通过下面的连接,找到前面的文章

    知识管理系统Data Solution研发日记之一 场景设计与需求列出

    知识管理系统Data Solution研发日记之二 应用程序系列

    知识管理系统Data Solution研发日记之三 文档解决方案

    知识管理系统Data Solution研发日记之四 片段式数据解决方案

    知识管理系统Data Solution研发日记之五 网页下载,转换,导入

    每一篇文章都试图从一个角度来分析这个系统的目的,设计思路。至于源代码,并没有什么特别的难度,问题的关键在于思路,找到了合适的解决方案,实现起来就相对容易一些。这篇文章讲解窗体设计器的主要内容。

    image

    设计器生成的的窗体文件,可以以二种方式保存,一种是源代码方式,C#,VB.NET代码的形式,另一种是XML格式,这里采用的是XML格式保存窗体设计格式。如果你对此并不熟悉,请通过查看文章《基于窗体设计器的企业管理软件开发工具》来了解更多的内容。

    在Windows Forms的开发中,BindingSource控件扮演着数据与控件连接的桥梁,而且是双向的数据绑定。这句话在学习ASP.NET时,一直不得其解,双向的数据绑定与单向的有什么区别。用直白的话说,双向的数据绑定,可以让控件中被用户修改的数据,重新写到绑定的数据源中,在窗体的保存功作中,可以保存用户修改的数据。双向的数据绑定可以节省大量的数据绑定代码,想像一下,在刚学编程时,经常写出这样的代码

    protected override void OnLoad()
    {
        txtUserName.Text=user.UserName;
        txtEmal.Text=user.Email;
    }
    
    protected override void OnClosing()
    {
          user.UserName=txtUserName.Text;
          user.Emal=txtEmail.Text;
    }

    在窗体打开时,需要从数据实体类型中,绑定数据到控件中,在窗体关闭时,再从控件的值写到数据实体类型中。如果没有双向的数据绑定,界面中会大量的重复这样的代码。

    先来看一个,读取单一个数据表的情况。比如,只读取采购单PUORDH一个表。在上图中的窗体设计器中,有两个FlexDataTable控件,它用来获取数据源。它的Name就是数据库中的表名,SQL属性是读取数据的SQL语句,比如有一个表是PUORDH(采购单),那么需要为它写SQL属性为SELECT * FROM PUORDH。理论上,在知道表名之后,是不需要写SQL属性的,因为可以生成默认的SELECT语句,出于效率的考虑,可以简化对SQL的编写,比如上面的窗体,它只读取PUORD的Ref No.和Vendor,这时,如果自动生成的SQL语句还是SELECT * FROM PUORDH,则效率损失很多,其它的不需要的字段也被读取到内存中。所以,FlextDataTable的SQL属性,可来用优化SQL性能,当它的值是空时,窗体设计器会自动生成SELECT * FROM PUORDH。

    再来看一下,读取主从表的情况。如上图所示,主表PUORDH,明细表PUORDD,它们的关系存在于数据库中,是一对多关系。这时,数据绑定的关键代码是这三行

    this.bsH.DataSource = this.DataSet;
    //this.bsD.DataSource=this.DataSet;
    this.bsD.DataSource =bsH;
    this.bsD.DataMember = "FK_PUORDD_PUORDH";

    表头的数据仍然是DataSet,初试化窗体时,根据FlexDataTable表名和它的SQL属性,读取数据到DataSet中。从表的数据如果是DataSet,没有错,但是没有正常显示出主表与从表的数据关联数据,它会选出所有的从表数据。所以,后面两行代码是绑定从表数据的关键。窗体设计器在生成CS源代码时,则需要生成正确的主从数据关系绑定代码。

    在生成主从数据关系方面,XSD是首选的方案,参考下面的调用代码,它可以生成包含关系的XSD文件

    string connectionString = "data source=(local);initial catalog=Emp5;integrated security=SSPI;persist security info=False;packet size=4096";
    string destinationFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, xsdName);
    
    List<string> tables = new List<string>();
    foreach (IComponent comp in host.Container.Components)
           {
                    if (comp is FlexDataTable)
                     {
                                 tables.Add(comp.Site.Name);
                        }
            }                       
    DatasetGeneratorForm dlgXsd = new DatasetGeneratorForm(connectionString, destinationFile, false, "CS", tables);
    dlgXsd.GenerateXsdSource();

    窗体设计器正是从这个生成的XSD文件中获取到表与表之间的关系,以生成上面提到的主从表的数据绑定代码。

    在窗体设计器生成代码方面,CodeDom是首选的代码生成技术。这主要归咎于它可以以一套代码,同时生成C#,VB.NET两套代码,这种灵活性比硬编码的字符串拼凑,效果要好很多。代码示例如下

    //this.DataAdapter = da;
    CodeVariableReferenceExpression da = new CodeVariableReferenceExpression("da");
    CodePropertyReferenceExpression thisda = new CodePropertyReferenceExpression(new        CodeThisReferenceExpression(), "DataAdapter");
    CodeAssignStatement  as1 = new CodeAssignStatement(thisda, da);
    method.Statements.Add(as1);    

    为了写一个赋值语句,竟然用了四行代码,而且CodeDom调试时,也不可以看到它生成的目标代码的模样。这与调试带参数的SQL语句的体验差不多,无法得知最终要发送到服务器的SQL语句的模样。好在有MSDN和大量的在线资源,可以很容易的获取到一个C#语句如何用CodeDom表达出来。而且大部分情况是,你写对了CodeDom语句,感觉对了,它运行时的结果,就是对的。微软的人真了不起,竟然创造了CodeDom这种威力巨大的代码生成技术。

    再来看一下窗体间互操作的代码,打开一个窗体,可以用这条语句

    =Open("PURCHASE") 或是=Open("PURCHASE",this)

    带一个参数的Open方法,会以参数为XML文件名,拼凑成PURCHASE.XML字符串,到系统的指定目录中查找PURCHASE.XML窗体定义格式文件,读取并转化成窗体类型,显示出来;带二个参数的Open方法,会在系统指定的目录中,查找PURCHASE.dll程序集文件,反射它的类型成员,调用并显示了出来。这里也有个约定,窗体设计器生成的源代码文件,只包含一个类型定义,然后经过CodeDomProvider编译,生成窗体的程序集文件。

    继续看窗体设计器设计的窗体,它的另外几个按钮的Click事件的写法

    保存按钮的Click事件的写法是:=Save();

    删除按钮的Click事件的写法是:=Delete(bsH,bsD) ;

    创建按钮的Click事件的写法是:=New(bsH,bsD);

    在这里,完全不需要指定主外键,或是表与表之前的关联关系,所以这些,都由后台程序自动判断。这样做,也没有效率。读取数据的操作是把它读到一个DataSet中,然后依照FlexDataTable表名依次分配与绑定;保存操作会把数据写回到数据库中,依照DataSet中数据是否发生改变,这个写回数据库的过程,效率很低。当然,大多数的情况,是用来查看数据库中的数据,而不是编辑数据,依照这个标准,窗体设计器也达到了它的目的。

    把这几条技术整合到一起,就完成了窗体设计器的开发。我在思考这些关系时,通常零乱的,不完整的,设计的过程也是代码演化,思路调整的过程。也许你不知道我这里讲的是什么内容,或许你有更好的实现方法,欢迎反馈。

  • 相关阅读:
    ovs 数据包的处理过程
    Docker常用命令
    java中的各种锁详细介绍
    Oracle中的一些基本操作
    Java连接MySQL8.0以上版本数据库方式
    关于Maven+Tomcat7下cannot be cast to javax.servlet.Servlet问题的解决办法
    冒泡排序及优化详解
    Java集合类的概述
    关于java中构造方法、实例初始化、静态初始化执行顺序
    git push 时 failed to push some refs 的解决方案
  • 原文地址:https://www.cnblogs.com/JamesLi2015/p/2225492.html
Copyright © 2011-2022 走看看