文/lijun4017  出处/博客园

其实这是我的一个两年前的项目中用到的东西,今天刚好翻以前的代码,看到,觉得也是自己想出来的东西,写写也无妨,哪怕是为了填充我空虚的blog。这个是一个智能客户端,但是里面涉及的表单非常之多,统计一下,有200个张。本来也不是问题,用FORM一个一个画也能够画出来,但是这样有几个缺点,一方面导致智能客户端的dll变的比较大,每次更新的时候,都要下载整个dll;一方面分工不好分,原来那个公司那时候只有我用过winform,老板就把这个任务分配给我了。但是我一个人,要做那么多的表单,而且在比较短的时间内,也不是说不可能,太累了。我想想看能不能有其他方法。

当时XFORM的概念相当热,我也看了一些资料,觉得还是不太成熟,没有敢用。

后来看了微软office2007中的infopath,感觉功能非常强,它可以实现用infopath设计表单,然后用表单控件把表单嵌入到winform中去,并且可以实现表单中的数据加载和保存功能。但是唯一的遗憾就是如果要使用它,就必须要客户机器上安装office2007,这样就不太现实了。

最后来想到的是用xml+xslt是动态生成静态页面,然后把静态页面嵌入在winform的浏览器控件里面,并且屏蔽一些浏览器控件的一些属性,看起来就和winform设计的表单差不多了。这样就方便多了,我可以叫美工帮我设计表单,叫其他的asp.net的程序员帮忙做XML和XSLT以及里面的javascript脚本。后来的项目进展说明了,这种方式真的大大的提高了工作效率,也让我轻松了不少,嘿嘿,又偷懒了。

下面我说说具体的过程吧。
1.首先我在设计表的时候,把整个表单的内容设计成XML类型的字段,当然,其他需要搜索的字段还是要单独建字段,并且保存xslt文件的版本号。
2.设计表单的XML结构,下面是示例。
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <!--现场会议记录-->
  3. <meetnote>
  4.   <enterprise></enterprise>
  5.   <!--会议名称-->
  6.   <meets>
  7.     <meet>
  8.       <name>meet1</name>
  9.       <checked>false</checked>
  10.     </meet>
  11.     <meet>
  12.       <name>meet2</name>
  13.       <checked>false</checked>
  14.     </meet>
  15.     <meet>
  16.       <name>meet3</name>
  17.       <checked>false</checked>
  18.     </meet>
  19.   </meets>
  20.   <compere />
  21.   <recorder />
  22.   <address />
  23.   <meetdate />
  24.   <content />
  25. </meetnote>
复制代码
3.设计表单的XSLT文件,下面是示例。
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  3.                 xmlns:msxsl="urn:schemas-microsoft-com:xslt"               
  4.                 version="1.0" >
  5.   <xsl:template match="/">
  6.     <html>
  7.       <head>
  8.         <link href="../css/xmltable.css" rel="stylesheet" type="text/css" />
  9.         <script language="javascript">
  10.           //使用客户端日期JS脚本初始化

  11.           var date = new Date();
  12.           var  Fun_Year = date.getYear();
  13.           var  Fun_Month = date.getMonth()+1;
  14.           var  Fun_Day = date.getDate();
  15.         </script>
  16.         <script language="javascript" src="../javascript/calendar.js"></script>
  17.         <script language="javascript" src="../javascript/check.js"></script>
  18.         <script language="javascript" src="../javascript/common.js"></script>
  19.         <script language="javascript">
  20.           function validate()
  21.           {
  22.           var errorinfo="";
  23.           if(clearSpace(txtcompere.value)=="")
  24.           {
  25.           errorinfo += "主持人为空\n";
  26.           }
  27.           if(clearSpace(txtaddress.value)=="")
  28.           {
  29.           errorinfo+= "会议地点为空\n";
  30.           }
  31.           if(clearSpace(txtrecorder.value)=="")
  32.           {
  33.           errorinfo+="记录人为空\n";
  34.           }
  35.           if(clearSpace(txtmeetdate.value)=="")
  36.           {
  37.           errorinfo += "会议时间为空\n";
  38.           }
  39.           if(clearSpace(txtcontent.innerText)=="")
  40.           {
  41.           errorinfo+= "会议内容为空\n";
  42.           }
  43.           //会议名称
  44.           if(txtmeet1.checked != true && txtmeet2.checked != true && txtmeet3.checked != true)
  45.           {
  46.           errorinfo+= "请选择会议名称\n";
  47.           }
  48.           if(errorinfo=="")
  49.           {
  50.           return true;
  51.           }
  52.           else
  53.           {
  54.           window.external.ShowErrorMessage(errorinfo);
  55.           return false;
  56.           }

  57.           }
  58.           //数据保存
  59.           function savetoxml()
  60.           {
  61.           var doc = new ActiveXObject("Msxml2.DOMDocument");
  62.           doc.async = false;
  63.           //调用c#方法获取xml文件路径
  64.           var xmlfilepath = window.external.GetXMLPathForJava();
  65.           doc.load(xmlfilepath);

  66.           //会议名称
  67.           doc.selectNodes("meetnote/meets/meet")[0].lastChild.text=(txtmeet1.checked==0)?'false':'true';
  68.           doc.selectNodes("meetnote/meets/meet")[1].lastChild.text=(txtmeet2.checked==0)?'false':'true';
  69.           doc.selectNodes("meetnote/meets/meet")[2].lastChild.text=(txtmeet3.checked==0)?'false':'true';

  70.           doc.selectSingleNode("meetnote/compere").text=txtcompere.value;
  71.           doc.selectSingleNode("meetnote/recorder").text=txtrecorder.value;
  72.           doc.selectSingleNode("meetnote/address").text=txtaddress.value;
  73.           doc.selectSingleNode("meetnote/meetdate").text=txtmeetdate.value;
  74.           doc.selectSingleNode("meetnote/content").text=txtcontent.innerText;

  75.           //调用c#方法保存xml文件
  76.           var examfiletype = window.external.GetExamFileType();
  77.           var examfilename = window.external.GetExamFileName();
  78.           window.external.Save(doc.xml,examfiletype,examfilename);
  79.           return true;
  80.           }
  81.         </script>
  82.         </head>
  83.       <body>
  84.         <xsl:apply-templates/>
  85.       </body>
  86.     </html>
  87.   </xsl:template>

  88.   <xsl:template match="meetnote">
  89.  
  90.     <table border="1" align="center" cellPadding="0" cellSpacing="0"  class="table">

  91.       <tr>
  92.         <td  class="td1"  colspan="4">
  93.           <div align="center" class="title">现场审核会议记录</div>
  94.         </td>
  95.       </tr>
  96.       <tr>
  97.         <td class="td2">
  98.           <span>受审核方:</span>

  99.           <xsl:value-of select="enterprise" />

  100.         </td>
  101.       </tr>
  102.       <tr>
  103.         <td class="td2">
  104.           <span>会议名称:</span>
  105.           <xsl:apply-templates select="meets/meet"/>
  106.         </td>
  107.       </tr>
  108.       <tr>
  109.         <td class="td2">
  110.           <span>主 持 人:</span>
  111.           <input style="WIDTH: 150px; " type="text" name="txtcompere">
  112.             <xsl:attribute name="value">
  113.               <xsl:value-of select="compere" />
  114.             </xsl:attribute>
  115.           </input>
  116.           <span>会议地点:</span>
  117.           <input style="WIDTH: 200px; " type="text" name="txtaddress">
  118.             <xsl:attribute name="value">
  119.               <xsl:value-of select="address" />
  120.             </xsl:attribute>
  121.           </input>
  122.         </td>
  123.       </tr>
  124.       <tr>
  125.         <td class="td2">
  126.           <span>记 录 人:</span>
  127.           <input style="WIDTH: 150px; " type="text" name="txtrecorder">
  128.             <xsl:attribute name="value">
  129.               <xsl:value-of select="recorder" />
  130.             </xsl:attribute>
  131.           </input>
  132.           <span>会议时间:</span>
  133.           <input style="WIDTH: 100px; " type="text" name="txtmeetdate" onfocus="calendar();" id="txtmeetdate">
  134.             <xsl:attribute name="value">
  135.               <xsl:value-of select="meetdate" />
  136.             </xsl:attribute>
  137.           </input>
  138.         </td>
  139.       </tr>
  140.       <tr>
  141.         <td  valign="top" class="td2">
  142.           <span>会议内容:</span>
  143.           <br/>
  144.           <textarea style="WIDTH: 100%;HEIGHT:150px " type="text" name="txtcontent">
  145.               <xsl:value-of select="content" />
  146.           </textarea>
  147.         </td>
  148.       </tr>
  149.     </table>
  150.   </xsl:template>
  151.   <!--会议名称-->
  152.   <xsl:template match="meets/meet">
  153.     <xsl:if test="name='meet1'">
  154.       <input type="checkbox" name="txtmeet1" id="txtmeet1" onclick="radiobutton(this,'txtmeet')">
  155.         <xsl:if test="checked='true'">
  156.           <xsl:attribute name="checked">
  157.             checked
  158.           </xsl:attribute>
  159.         </xsl:if>
  160.       </input>
  161.       <span>首次会议</span>
  162.     </xsl:if>
  163.     <xsl:if test="name='meet2'">
  164.       <input type="checkbox" name="txtmeet2" id="txtmeet2" onclick="radiobutton(this,'txtmeet')">
  165.         <xsl:if test="checked='true'">
  166.           <xsl:attribute name="checked">
  167.             checked
  168.           </xsl:attribute>
  169.         </xsl:if>
  170.       </input>
  171.       <span>沟通会议</span>
  172.     </xsl:if>
  173.     <xsl:if test="name='meet3'">
  174.       <input type="checkbox" name="txtmeet3" id="txtmeet3" onclick="radiobutton(this,'txtmeet')">
  175.         <xsl:if test="checked='true'">
  176.           <xsl:attribute name="checked">
  177.             checked
  178.           </xsl:attribute>
  179.         </xsl:if>
  180.       </input>
  181.       <span>末次会议</span>
  182.     </xsl:if>
  183.   </xsl:template>
  184. </xsl:stylesheet>
复制代码
4.在XSLT文件中加入JS脚本,用户验证用户输入,收集表单数据,加载表单数据等。(这里涉及到JS代码和浏览器控件所在的winform窗体的代码的相互调用。)
1)首先把winform窗体的类加上这个属性[ComVisible(true)]

2) 在winform窗体里面写上public的方法
  1.         //取得xml文件路径(供javascript调用)
  2.         public string GetXMLPathForJava()
  3.         {         
  4.             return tempxmlfilepath;
  5.         }
复制代码
3)在XSLT文件里面的JS代码中调用这个方法
  1.   //调用c#方法获取xml文件路径
  2.         var xmlfilepath = window.external.GetXMLPathForJava();
复制代码
4)在XSLT文件中定义JS方法
  1.         //数据保存
  2.           function savetoxml()
  3.           {
  4.         }
复制代码
5)在winform窗体中调用JS方法
//调用JS方法
  1. Object result = webBrowser1.Document.InvokeScript("savetoxml");
复制代码
5.在显示页面的时候,我先使用下面的代码把XSLT和XML转换成HTML文件,存放在临时文件夹中,然后把浏览器控件的URL指向它。
  1.   XslCompiledTransform transForm = new XslCompiledTransform();
  2.             string xsltemplatepath = TemplateHelper.GetFactoryFormXSLTemplatePath(m_FileType, m_DataRow.xsl_version);

  3.             try
  4.             {
  5.                 transForm.Load(xsltemplatepath);
  6.                 transForm.Transform(tempxmlfilepath, temphtmlfilepath);
  7.             }
  8.             catch(Exception ex)
  9.             {
  10.                 LogError.Write(ex.Message + "\n" + ex.StackTrace);
  11.                 MessageBox.Show("模板文件加载出错!");
  12.                 this.Close();
  13.                 return;
  14.             }
  15.             webBrowser1.Navigate(temphtmlfilepath);
复制代码
6.在用户点击保存的时候,我通过XSLT中定义的JS代码,直接把用户保存的数据以XML的方式返回给winform的代码,然后保存到数据库中去。
  1. Object validateresult = webBrowser1.Document.InvokeScript("validate");
  2.             if (Convert.ToBoolean(validateresult) == true)
  3.             {
  4.                 Object result = webBrowser1.Document.InvokeScript("savetoxml");
  5.                 if (Convert.ToBoolean(result) == true)
  6.                 {
  7.                     this.Close();
  8.                 }
  9.                 else
  10.                 {
  11.                     MessageBox.Show("保存出错", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
  12.                     this.DialogResult = DialogResult.None;
  13.                 }
  14.             }
  15.             else
  16.             {
  17.                 this.DialogResult = DialogResult.None;
  18.             }
复制代码
7.删除刚才产生的临时文件。
TOP