设为首页 收藏本站
查看: 974|回复: 0

[经验分享] 【InfoPath应用场景:库存管理】在InfoPath Form Service利用WSS Web Service技术,通过VSTA代码把复杂表单写入Shar

[复制链接]

尚未签到

发表于 2015-9-28 07:28:47 | 显示全部楼层 |阅读模式
  企业中各式各样的表单是InfoPath最恰当的应用,但是有人总是抱怨InfoPath不够灵活,他们承认利用InfoPath设计表单可以高效地设计出最美观的表单,但是设计出的表单如何与数据库结合、如何与列表结合却是头疼的问题。一个包括了复杂“重复表”的InfoPath表单在列表库中就是一个文件,这让表单中的每行数据记录如何分别统计汇总呢?下面就给你一个解决这个问题的最佳答案。

  ● 应用的场景“出入库管理”:
  
  
应用场景功能要求:
  1 通过浏览器,来填写出入库单。
  2 按(物资名称+规格型号)查询,其出入库历史记录。
  3 统计分析,某个(物资名称+规格型号)共入库数量、共出库数量。
  
  下面给出一个入库单,出库单类似:
   
DSC0000.jpg
如上图,又有单独的字段又有重复表。

解决方案(对应上述1、2、3功能要求):
  1,InfoPath是可以完成的,而且完成得非常好。
  2,3 SharePoint列表是可以完成的,而且拉拉视图就搞定。
  
  如图所示,上述表单如果用“SharePoint列表库+SPD视图”来设计,基本是没有戏了,所以我们采用两个库,一个InfoPath表单库以来存储表单,以提供数据录入的界面(操作员接口),一个列表库存储表单中的记录,以提供统计、分析等功能(查询数据库)。然后采用VSTA的方式,在InfoPath的表单的“提交”编写代码,这个代码完成两种功能:1、把表单提交到表单库。2、把表单中的每一行入库(出库)物资,提交到另一个列表库中(为了方便,那些单独字段,比如入库单号、日期、发货人等要重复存储于每行记录中)。这种结构就类似于InfoPath+SQL的方式,只不过SQL比较麻烦,我换成了列表库。下面分别介绍

  要点1:使用InfoPath表单库来存储两个不同内容类型
  新建一个InfoPath库,把设计好的两个出入库InfoPath表单的内容类型(下文会介绍怎么设计)作为这个库的两个内容类型加进去,如图所示,并设置好这个文档库-设置-高级设置,中的“显示为网页”以启用InfoPath Form Service,如何设计代码后面再说,现在你创建一个空的InfoPath表单库就OK了。(图是最终效果)
   DSC0001.gif

  要点2:使用WSS列表库来统计汇总
  创建一个新的自定义列表库,也启动两个内容类型,“材料入库单”和“材料出库单”,入库记录的名全部使用InfoPath入库表单所有的、而且相同的栏名(为什么?为了以后编代码方便呀),本示例如下,入库记录也相同设置。PS:我把原来的标题设成隐藏的!体会一下用意哦。
   DSC0002.jpg

  统计的时候,可以按不同的需要建立不同的视图,如下图,按“物资名称(规格)”的格式进行分组统计:
DSC0003.jpg

下图是按出入库单号分组,你通过这个视图可以看见,原来在一个InfoPath表单中的多个记录,已经一条条乖乖进列表了。

DSC0004.jpg
  

  要点3:在VSTA代码中使用MOSS自带的WebService:Lists类下的UpdateListItems
  作用:提供InfoPath Form Service更新列表的一个手段。在Form Service中使用托管代码你是不能直接使用OM的UPDATE方法的,这是MOSS出于安全性的考虑,当然你可以在基于客户端的InfoPath中直接使用UPDATE没有问题。本解决方案使用的是MOSS WebService中的Lists类下的UpdateListItems方法。你可以参考相关的SDK。下面简单要介绍一下这个方法。
    返回批处理的XML结果 UpdateListItems(列表ID,批处理XML表达式);
  列表ID,就是你更新的列表的ID,以4个短线连结一32位字串,列表ID,你可以通过SPD打开列表的AllItems.aspx然后在源代码中查看<ListName这个字串,得到。
  批处理XML表达式,最简单的就是
    <Batch>
        <Method ID='1' Cmd='Delete'>
            <Field Name='ID'>1</Field>
        </Method>
        <Method ID='2' Cmd='New'>
            <Field Name='ID'>New</Field>
            <Field Name='Title'>新的记录标题</Field>
        </Method>
    </Bacth>
    这个批处理,共步操作,先删除了一个ID为1列表项,后新建了一个标题为"新的记录标题"的列表项。
  所有的Field名称都必须为列表的内部名称,就是@ADFDF_f3435这些东东。

  要点4:编写基于InfoPath浏览器表单的VSTA托管代码
  接上篇: 要点4: 如何在InfoPath的VSTA下编写代码,

"工具"->"提交选项"->"使用代码自定义操作"->"编辑代码",

在提交选项中插入以下自定义提交代码:


DSC0005.gif public void FormEvents_Submit(object sender, SubmitEventArgs e)
DSC0006.gif DSC0007.gif          DSC0008.gif {
DSC0009.gif             this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:ErrInfo", this.NamespaceManager).SetValue("");
            FormSave();

            if (this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:SaveError", this.NamespaceManager).Value == "true")
DSC00010.gif DSC00011.gif             {
                e.CancelableArgs.Message = "提交过程有失败,请查看错误信息";
                e.CancelableArgs.Cancel = true;
DSC00012.gif             }

            else
            {
               
                e.CancelableArgs.Cancel = false;
            }
            
            
DSC00013.gif         }  代码中使用了一个方法,FormSave(),这是一个自定的方法,其作用就是:

1 把表单提交进入表单库,
    如果是新建表单,使用不允许覆盖的提交方式.
    如果是更新以前的表单,使用可以覆盖的提交方式.

2 把表单的记录更新进入列表库,


    代码通过遍历表单中重复表的每一行数据,如果该行数据在"列表"中可以找到,即有相同的单号\名称\规格,那就采用Update方法,如果找不到,那就采用新建New.

   然后代码继续遍历"列表"中入库单号等于该入库单的项,如果列表中的项,新提交的表单中没有,说明使用者在使用InfoPath的时候把它删除了,那么就从"列表"中删除它!

3 错误处理,

private void FormSave()
        {
            // 在此处编写代码。

            string strResult = "";
            this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:SaveError", this.NamespaceManager).SetValue("false");

            try
            {

                //进行表单的保存操作,如果保存没有办法进行,就不进行记录的更新

                if (this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:isNew", this.NamespaceManager).Value == "true")
                {   //如果是新建表单,不允许覆盖库中的记录

                    ((FileSubmitConnection)this.DataConnections["新建提交"]).Execute();

                    this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:isNew", this.NamespaceManager).SetValue("false");
                }
                else
                    //如果不是新建表单,而是更新以前的表就,使用可以覆盖的提交
                    ((FileSubmitConnection)this.DataConnections["主提交"]).Execute();

                strResult += "入库单保存成功!\r\n";

                //读取列表的记录
                SPSite site = new SPSite("http://f2003-server/");
                SPList list = site.OpenWeb("/project").Lists["物资出入库记录"];

                //初始化WebService
                物资入库.myws.Lists listService = new 物资入库.myws.Lists();   //获得Lists对象

                listService.Credentials = System.Net.CredentialCache.DefaultCredentials;  //设置验证票

                listService.Url = "http://f2003-server/project/_vti_bin/Lists.asmx"; //非常重要,指定了下面所有的操作都是针对project这个子网站



                //遍历重复表group1中的每一项
                XPathNavigator NodeIter = this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:group1", this.NamespaceManager);

                //定义操作字串
                string strBatch = "";

                foreach (XPathNavigator myf in NodeIter.SelectChildren(XPathNodeType.Element))
                {
                    //对于重复表中的每一行,到列表去查找,如果找到就使用Update,找不到就使用New

                    SPQuery myQ = new SPQuery();

                    string QueryText = "<Where><And><And><Eq><FieldRef Name='" + list.Fields["入库单编号"].InternalName + "'/><Value Type='Text'>"
                                + MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:入库单编号", this.NamespaceManager).Value
                                + "</Value></Eq><Eq><FieldRef Name='" + list.Fields["物资名称"].InternalName + "'/><Value Type='Text'>"
                                + myf.SelectSingleNode("my:物资名称", NamespaceManager).Value + "</Value></Eq></And>"
                                + "<Eq><FieldRef Name='" + list.Fields["规格型号"].InternalName + "'/><Value Type='Text'>"
                                + myf.SelectSingleNode("my:规格型号", NamespaceManager).Value + "</Value></Eq>"
                                + "</And></Where>";

                    myQ.Query = QueryText;

                    SPListItemCollection items = list.GetItems(myQ);

                    if (items.Count == 0)
                    {
                        //如果没有找到就新增

                        strBatch += "<Method ID='" + myf.SelectSingleNode("my:序号", NamespaceManager).Value + "' Cmd='New'><Field Name='ID'>New</Field>";

                    }

                    else
                    {
                        //如果找到了就更新

                        strBatch += "<Method ID='" + myf.SelectSingleNode("my:序号", NamespaceManager).Value + "' Cmd='Update'><Field Name='ID'>" + items[0].ID.ToString() + "</Field>";
                    }

                    //扁历所有列表的字段,如果与表单的字段名称相同,就更新该字段
                    foreach (SPField field in list.Fields)
                    {
                        //重复表内的字段
                        foreach (XPathNavigator myfield in myf.SelectChildren(XPathNodeType.Element))

                            //比较相同
                            if (field.Title == myfield.Name.Substring(myfield.Name.IndexOf(":") + 1))
                            {
                                strBatch += "<Field Name='" + field.InternalName + "'>" + myfield.Value + "</Field>";
                            }


                        //重复表外的,单号、收货人、日期等等字段
                        foreach (XPathNavigator myfield in this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields", this.NamespaceManager).SelectChildren(XPathNodeType.Element))

                            if (field.Title == myfield.Name.Substring(myfield.Name.IndexOf(":") + 1))
                            {
                                strBatch += "<Field Name='" + field.InternalName + "'>" + myfield.Value + "</Field>";
                            }




                    }

                    strBatch += "</Method>";
                }


                //下面检查,此次表单编辑,是否删除了记录
                SPQuery myQ2 = new SPQuery();



                string QueryText2 = "<Where><Eq><FieldRef Name='" + list.Fields["入库单编号"].InternalName + "'/><Value Type='Text'>"
                            + MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:入库单编号", this.NamespaceManager).Value
                            + "</Value></Eq></Where>";

                myQ2.Query = QueryText2;

                int MethodId = NodeIter.SelectChildren(XPathNodeType.Element).Count + 1;

                SPListItemCollection allItems = list.GetItems(myQ2);
                foreach (SPListItem item in allItems)
                {
                    bool stillExist = false; //原来记录中的项,在新的表单中还存在?

                    foreach (XPathNavigator myf in NodeIter.SelectChildren(XPathNodeType.Element))
                    {
                        if (item["物资名称"].ToString() == myf.SelectSingleNode("my:物资名称", this.NamespaceManager).Value)
                        {
                            //物资名称相同,规格型号都为空
                            if (item["规格型号"] == null && (myf.SelectSingleNode("my:规格型号", this.NamespaceManager).Value == null || myf.SelectSingleNode("my:规格型号", this.NamespaceManager).Value == ""))
                                stillExist = true;
                            else
                            {
                                if (item["规格型号"] != null)
                                    if (item["规格型号"].ToString() == myf.SelectSingleNode("my:规格型号", this.NamespaceManager).Value)
                                        stillExist = true;
                            }

                        }
                    }

                    if (!stillExist)
                    {//如果老项已经在新的编辑过程中删除了,那么就执行删除Method
                        
                        strBatch += "<Method ID='" + MethodId.ToString() + "' Cmd='Delete'><Field Name='ID'>" + item.ID.ToString() + "</Field></Method>";
                        
                    }



                }



                XmlDocument xmlDoc = new System.Xml.XmlDocument();

                System.Xml.XmlElement elBatch = xmlDoc.CreateElement("Batch");

                elBatch.SetAttribute("OnError", "Continue");


                elBatch.InnerXml = strBatch;


                XmlNode ndReturn = listService.UpdateListItems("676CFD44-76D0-4161-966D-DA1B55CB6CD3", elBatch);



                foreach (XmlNode ndResult in ndReturn.ChildNodes)
                {


                    if (Convert.ToInt32(ndResult.FirstChild.Value) == 0)

                        strResult += "序号:" + ndResult.Attributes["ID"].Value.ToString().Replace("New", "新建").Replace("Update", "更新").Replace("Delete", "删除") + "成功!";
                    else
                    {
                        strResult += "序号:" + ndResult.Attributes["ID"].Value.ToString().Replace("New", "新建").Replace("Update", "更新").Replace("Delete", "删除") + "失败!(代码" + Convert.ToInt32(ndResult.FirstChild.Value) + ")";
                        this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:SaveError", this.NamespaceManager).SetValue("true");
                    }


                }




                this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:ErrInfo", this.NamespaceManager).SetValue(strResult);
            }
            catch (Exception ex)
            {
                this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:SaveError", this.NamespaceManager).SetValue("true");
                this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:ErrInfo", this.NamespaceManager).SetValue(ex.Message);
               
            }


        }  
在表单的启动事件,用来设置IsNew变量的状态。


   public void FormEvents_Loading(object sender, LoadingEventArgs e)
        {
            // 在此处编写代码。

            if(!this.New)
                this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:isNew", this.NamespaceManager).SetValue("false");
            else
                this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:isNew", this.NamespaceManager).SetValue("true");
                                    
        }  

代码事项:使用了三个表单字段来进行状态维护,IsNew,SaveError,ErrInfo,

1 isNew,用来判断这个表单操作,是不是新建.平时当然可以使用表单的this.New来判断,但是由于是没有使用"保存",而使用了了提交到表单库的操作,你提交进去表单库后,this.New不会变成False.

2 SaveError,判断整个操作是否成功,如果有一个记录没有成功更新,也为True;

3 ErrInfo,如果失败,就显示失败信息,这个在表单中有一个文本框与之帮定.



要点5:事件处理程序:处理删除表单表单操作

  表单内部中的更新(插入、删除、更新)都可以反应在&#8220;列表&#8221;中,那么使用者如果删除表单文件呢?
   大家可以自己思考哦。



原文链接:http://blog.lickies.cn/DocLib/[%20InfoPath应用场景:库存管理%20]%20在InfoPath%20Form%20Service利用WSS%20Web%20Service技术,通过VSTA代码把复杂表单写入SharePoint列表数据库%20(一).aspx

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-119645-1-1.html 上篇帖子: 在Sharepoint 2010 中给HTML内容编辑器部件自定义CSS样式 下篇帖子: 国内市场主流专业的sharepoint开发公司分析比较及推荐
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表