好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Winform的Excel表格

Winform的Excel表格

利用FarPoint Spread表格控件,构造Winform的Excel表格界面输入

因有一个业务需要在Winform界面中,以类似Excel表格界面中录入相关的数据(毕竟很多时候,客户想利用成熟的软件体验来输入他们想要的东西),其中界面需要录入基础信息,列表信息,图片信息等,综合这些就是例如下面这样的界面效果。本文主要针对如何利用FarPoint Spread表格控件实现类似Excel界面丰富数据的保存及显示,以及在使用过程中的一些经验心得,希望对大家在开发Winform的Excel数据录入和显示方面的开发有一定帮助。

从以上的界面分类可以看到,大致可以分为几个类型的数据,一个是基础字段数据,一个是有多行的列表数据,一个是图片数据,还有就是备注信息的显示录入了。下面我来分类介绍这些功能的实现。

1、类似Excel的列表总体界面设计

首先,这个列表需要在Winform的界面中进行设计,拖入一个Farpoint控件到Winform界面上,设置好布局等属性,然后在右键菜单上启动Spread Designer就可以设计相关的Excel样式表格的内容了。

注意,这里界面一般是在窗体中设计的,当然你的内容可以通过复制粘贴的方式,从Excel文档拷贝过来,效果看起来一样的,非常不错。不过,虽然Farpoint Spread控件提供了一个另存为Xml文件的操作,并且可以通过API,Open一个XML文件,不过Open的XML文件后,好像内容不能进行修改的,而且类型CellType也是Null的,所以如果要在一个窗体上动态加载布局好像做不到,至少我没有做到。不过对于开发来说,我们在设计时刻,设计好Excel样式的列表界面,也未尝不是一件好事。

2、下拉列表的绑定

在Excel列表中,我们很多时候,为了输入的方便,需要通过下拉列表方式输入内容,这样可以提高速度和用户体验,但这些内容必须是通过数据库内容进行绑定的,Farpoint Spread控件是如何做到绑定下拉列表的数据的呢。首先Farpoint Spread控件由很多输入的内容,其中就包括有ComoBox类型,如下所示。

我们在指定下拉的类型后,Excel列表的显示方式也跟着变化为下面样式了。

以上打勾的就是我们下一步需要绑定列表数据的列表了,绑定列表的数据也不麻烦,就是需要明确Cell的序号,绑定给他数据源就可以了,不过说实话,经常要数着Cell的行列号是什么数字,有点不方便。

         private   void   BindDict()
        {
            FarPoint.Win.Spread.Cell cell;

              //  品名 
            cell =  this .fpSpread1_Sheet1.Cells[ 1 , 9  ];
            FarPoint.Win.Spread.CellType.ComboBoxCellType productType  =  new   FarPoint.Win.Spread.CellType.ComboBoxCellType();
            productType.BindDictItems(  "  品名  "  );
            cell.CellType  =  productType;

              //  客户名 
            cell =  this .fpSpread1_Sheet1.Cells[ 4 ,  8  ];
            FarPoint.Win.Spread.CellType.ComboBoxCellType customerType  =  new   FarPoint.Win.Spread.CellType.ComboBoxCellType();
            customerType.BindDictItems(  "  客户名  "  );
            cell.CellType  =  customerType;

              //  款号 
            cell =  this .fpSpread1_Sheet1.Cells[ 1 ,  12  ];
            FarPoint.Win.Spread.CellType.ComboBoxCellType styleType  =  new   FarPoint.Win.Spread.CellType.ComboBoxCellType();
            styleType.BindDictItems(  "  款号  "  );
            cell.CellType  =  styleType;

              //  面料 
            cell =  this .fpSpread1_Sheet1.Cells[ 1 ,  15  ];
            FarPoint.Win.Spread.CellType.ComboBoxCellType materialType  =  new   FarPoint.Win.Spread.CellType.ComboBoxCellType();
            materialType.BindDictItems(  "  面料  "  );
            cell.CellType  =  materialType;

        } 

其中代码的BindDictItems我用了扩展方法,所以能通过对象直接调用,具体的函数代码如下所示,就是调用字典业务类获取数据,赋值给Items属性即可,注意其中的Edittable最好选择为true,否则它只是显示里面列表的内容,类似DropdownList那样。

         ///   <summary> 
         ///   绑定下拉列表控件为指定的数据字典列表
          ///   </summary> 
         ///   <param name="combo">  下拉列表控件  </param> 
         ///   <param name="dictTypeName">  数据字典类型名称  </param> 
         public   static   void  BindDictItems( this  FarPoint.Win.Spread.CellType.ComboBoxCellType combo,  string   dictTypeName)
        {
            Dictionary < string ,  string > dict = BLLFactory<DictData> .Instance.GetDictByDictType(dictTypeName);
            List < string > listData =  new  List< string > ();
              foreach  ( string  key  in   dict.Keys)
            {
                listData.Add(key);
            }
            combo.Items  =  listData.ToArray();
            combo.Editable  =  true  ;
        }  

3、如何构造界面自定义录入

为了输入方便,对于一些例如弹出框选择内容,图片编辑,备注内容(很长的时候)的编辑,这些一般来说,我们通过自定义界面来录入比较好,比较Excel样式的界面,录入单元格很小,也有时候实现不了的。所以通过制定控件单元格的单击事件,用来处理特殊录入信息的操作。

 this .fpSpread1.CellClick +=  new  FarPoint.Win.Spread.CellClickEventHandler(fpSpread1_CellClick);

展开界面部分给大家看看,就是很把内容

         void  fpSpread1_CellClick( object   sender, FarPoint.Win.Spread.CellClickEventArgs e)
        {
            FarPoint.Win.Spread.Cell cell  =  this  .fpSpread1_Sheet1.Cells[e.Row, e.Column];
            fpSpread1_Sheet1.SetActiveCell(e.Row, e.Column);

              if (e.Column ==  14  && e.Row ==  6  )
            {
                  #region  图片操作 
                FrmImageEdit dlg  =  new   FrmImageEdit();
                  if  (! string  .IsNullOrEmpty(ID))
                {
                    dlg.ID  =  ID;
                    dlg.IsNew  =  false  ;
                }
                  else  
                {
                    dlg.ID  =  NewID;
                    dlg.IsNew  =  true  ;
                }
                dlg.OnDataSaved  +=  new   EventHandler(dlgPicture_OnDataSaved);
                dlg.ShowDialog(); 
                  #endregion  
            }
              else   if  (e.Column ==  1  && e.Row ==  42  )
            {
                  #region  注意事项
                 object  value =  this  .fpSpread1_Sheet1.Cells[e.Row, e.Column].Value;
                  if  (value !=  null  )
                {
                    FrmEditNote dlg  =  new   FrmEditNote();
                    dlg.txtContent.Text  =  value.ToString();
                      if  (dlg.ShowDialog() ==  System.Windows.Forms.DialogResult.OK)
                    {
                          this .fpSpread1_Sheet1.Cells[e.Row, e.Column].Value =  dlg.txtContent.Text;
                    }
                } 
                  #endregion  
            } 

例如,对于下拉列表内容,需要进行弹出式选择内容,如下界面所示。

对于图片单元格,单击就可以弹出下面的窗体,方便编辑或者查看。

对于备注内容,我们让他弹出一个窗体,更好展现和编辑。

4、数据的显示和保存

对于普通的主表数据字段的显示很简单,把内容赋值给对应的单元格Text属性即可,如下所示。

         ///   <summary> 
         ///   数据显示的函数
          ///   </summary> 
         public   void   DisplayData()
        {
              if  (! string  .IsNullOrEmpty(ID))
            {
                  #region  显示信息 
                CraftHeaderInfo info  = BLLFactory<CraftHeader> .Instance.FindByID(ID);
                  if  (info !=  null  )
                {
                      this .fpSpread1_Sheet1.Cells[ 1 ,  9 ].Text =  info.ProductName;
                      this .fpSpread1_Sheet1.Cells[ 1 ,  12 ].Text =  info.StyleNo;
                      this .fpSpread1_Sheet1.Cells[ 1 ,  15 ].Text = info.Material;

保存的时候,把对应的内容保存到实体类进行数据保存操作即可。

         ///   <summary> 
         ///   编辑或者保存状态下取值函数
          ///   </summary> 
         ///   <param name="info"></param> 
         private   void   SetInfo(CraftHeaderInfo info)
        {
            info.ProductName  =  this .fpSpread1_Sheet1.Cells[ 1 ,  9 ].Text; //  品名 
            info.StyleNo =  this .fpSpread1_Sheet1.Cells[ 1 ,  12 ].Text; //  款号 
            info.Material =  this .fpSpread1_Sheet1.Cells[ 1 ,  15 ].Text; //  面料 

更多数据的时候,我们把内容保存分开,各个函数负责不同的部分即可,在主表保存后继续保存其他部分的内容,例如红色部分就是其他部分的保存操作。

         private   void  btnSave_Click( object   sender, EventArgs e)
        {
              if  (! string  .IsNullOrEmpty(ID))
            {
                CraftHeaderInfo info  = BLLFactory<CraftHeader> .Instance.FindByID(ID);
                  if  (info !=  null  )
                {
                    SetInfo(info);

                      try  
                    {
                          #region  更新数据
                         bool  succeed = BLLFactory<CraftHeader> .Instance.Update(info, info.ID.ToString());
                          if   (succeed)
                        {
                             SaveProcess(info.ID);
                            SaveAccessories(info.ID);
                            SaveIndicateSize(info.ID);
                            SaveColorPair(info.ID);

                               //  可添加其他关联操作 
                            ProcessDataSaved( this .btnSave,  new   EventArgs());

                            MessageDxUtil.ShowTips(  "  保存成功  "  );
                        }
                          #endregion  
                    }
                      catch   (Exception ex)
                    {
                        LogTextHelper.Error(ex);
                        MessageDxUtil.ShowError(ex.Message);
                    }
                }
            }
              else  
            { 

例如工艺过程是一个列表数据,保存的时候,需要指定行列的属性进行操作,而且我们添加一个Seq的序列号,用来保存内容的顺序,这样加载的时候,我们就按照这个循序进行加载显示,否则会出现问题。

         private   void  SaveProcess( string   headerId)
        {
              string  condition =  string .Format( "  Header_ID = '{0}'   "  , headerId);
            List <CraftProcessInfo> list = BLLFactory<CraftProcess> .Instance.Find(condition);
              //  (e.Column == 1 && (e.Row >= 6 && e.Row < 30)) 
             int  i =  0  ;
              for  ( int  row =  6 ; row <  30 ; row++ )
            {
                CraftProcessInfo info  = GetProcess(i++ , list);
                info.Header_ID  =  headerId;

                  int  col =  0  ;
                info.HandNo  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.Process  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.Models  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.NeedleWork  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.Flower  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.DownLine  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.PinCode  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.KnifeGate  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.Note  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.Item1  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.Item2  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.Item3  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;

                BLLFactory <CraftProcess> .Instance.InsertUpdate(info, info.ID);
            }
        } 

其中GetProcess函数,就是一个列表中查找对应顺序的内容,如果有,那么我们更新这个对应顺序的内容,如果没有,那么我们认为它是新的数据,这样就新增到数据库中,所以最后用了InserUpdate就是这个道理。其中GetProcess函数逻辑代码如下所示。

         private  CraftProcessInfo GetProcess( int  index, List<CraftProcessInfo>  list)
        {
            CraftProcessInfo info  =  new   CraftProcessInfo();
              if  (list.Count >  index)
            {
                info  =  list[index];
            }
            info.Seq  = index +  1 ; //  重新调整顺序号 

             return   info;
        }  

另外注意的时候,有些单元格是合并列的,所以一定要注意算好他的行列号哦。有些地方可能需要跳行。

         private   void  SaveAccessories( string   headerId)
        {
              string  condition =  string .Format( "  Header_ID = '{0}'   "  , headerId);
            List <AccessoriesInfo> list = BLLFactory<Accessories> .Instance.Find(condition);
              //  (e.Column == 1 && (e.Row >= 31 && e.Row < 35)) 
             int  i =  0  ;
              for  ( int  row =  31 ; row <  35 ; row++ )
            {
                AccessoriesInfo info  = GetAccessories(i++ , list);
                info.Header_ID  =  headerId;

                  int  col =  1  ;
                info.Name  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.Consumption  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.Position  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                col ++; //  空跳一列 
                info.Item1 =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                col ++; //  空跳一列 
                col++; //  空跳一列 
                info.Item2 =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.Item3  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.Item4  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.Item5  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;
                info.Item6  =  this .fpSpread1_Sheet1.Cells[row, col++ ].Text;

                BLLFactory <Accessories> .Instance.InsertUpdate(info, info.ID);
            }
        } 

5、Excel表格的数据打印及导出。

使用这个Farpoint Spread的空间,对于里面的内容进行打印或者导出Excel非常方便,代码也不多,如下所示。

         private   void  btnPrint_Click( object   sender, EventArgs e)
        {
            PrintInfo pi  =  new   PrintInfo();
            pi.Header  =  "  成衣工艺单  "  ;
            pi.JobName  =  "  成衣工艺单  "  ;
            pi.Orientation  =  PrintOrientation.Auto;
            pi.PageOrder  =  PrintPageOrder.Auto;
            pi.ShowPrintDialog  =  true  ;
            pi.PrintNotes  =  PrintNotes.AtEnd;

              for  ( int  i =  0 ; i <  this .fpSpread1.Sheets.Count; i++ )
            {
                pi.ShowPrintDialog  = (i ==  0  );
                  this .fpSpread1.Sheets[i].PrintInfo =  pi;
                fpSpread1.PrintSheet(i);
            }
        }

          private   void  btnExport_Click( object   sender, EventArgs e)
        {
              string  file = FileDialogHelper.SaveExcel( "  成衣工艺单.xls  "  );
              if  (! string  .IsNullOrEmpty(file))
            {
                  try  
                {
                      bool  success =  this  .fpSpread1.SaveExcel(file);
                      if   (success)
                    {
                          if  (MessageDxUtil.ShowYesNoAndTips( "  导出成功,是否打开文件?  " ) ==  System.Windows.Forms.DialogResult.Yes)
                        {
                            System.Diagnostics.Process.Start(file);
                        }
                    }
                }
                  catch   (Exception ex)
                {
                    LogTextHelper.Error(ex);
                    MessageDxUtil.ShowError(ex.Message);
                }
            }
        } 

导出的效果和界面显示的效果基本上一致的,而且图片等特殊的格式,也是正常保留在Excel里面,总体感觉不错。

最后附上这个系统的一些截图作为补充了解。

 

主要研究技术:代码生成工具、Visio二次开发、送水管理软件等共享软件开发
专注于 Winform开发框架 、WCF开发框架的研究及应用。
  转载请注明出处:
撰写人:伍华聪   http://www.iqidi.com  
    

 

 

 

 

标签:  WinForm界面开发

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于Winform的Excel表格的详细内容...

  阅读:51次

上一篇: Unix/Linux命令

下一篇:Django & Tornado