← 返回所有博客文章

基于“五步实现系统主页面”系列文章:

本文实现了一个Spread版数据分析系统主页面的简单原型。

在构建以数据分析为核心的系统中,有很多关键环节需注意。如,在控件套装的选型和评估中,务必要考虑3个关键业务需求环节:

  • 数据录入:表单数据逐条录入数据、Excel批量导入数据、在线编辑修改数据
  • 数据分析:类似Excel模板公式数据分析、类似Excel图表数据分析
  • 数据导出:PDF格式、Excel格式、CSV格式等
      基于此,本文选择了

Spread for WinForms 

    表格产品来构建原型系统:
      1

全球销量第一的表格控件,全面的中文化

    :使得系统更加符合中国的国内市场:开发人员和一线用户
      2

类似Excel的强大功能

    : 全面兼容Excel的操作方式,非常符合数据分析行业从业人员的习惯,系统易用性好
      3

可视化设计器

    :极大的方便了二次开发和业务需求人员进行无损的原型设计--业务人员设计UI后存储为XML,开发人员针对XML二次实现数据读取、呈现、持久化,极大的提高了研发各个环节的沟通效能。

开发环境:

1. Window 7 64位英文系统

2. Visual Studio 2012 SP3 英文版 (C#.net)   .NetFramework 4.0  (注: Visual Studio 2010可用源码)

3. Spread for WinForms 全球销量第一的表格控件,类似Excel的强大功能

原型系统采用左侧导航菜单,其中分为5个模块进行呈现业务:

  • 报表设计器
  • 财务报表操作
  • 2D图表呈现
  • Excel数据导入
  • 信息查询表单
  •  

spread_MainForm

 

Step 1: 报表设计器

 

Spread是世界上最强大、最畅销的.NET表格控件,它提供了灵活开放的对象模型和50,000个以上的API,使得用户拥有定制几乎所有元素和接口的能力。开发人员通过将Spread表格控件嵌入到.NET应用程序中,可以实现Microsoft Excel的绝大部分功能。

Spread-Design

Spread设计器用来设计并快速创建一个表单原型。通过其直观、易用的界面,在设计阶段对表单的外观进行定制,从而缩短开发时间。 Spread 设计器可为表单创建一个快照。当所有的更改完成后,所有可直接应用于工作表单。
Spread 设计器支持打开已有设计文件并将设计更改保存为文件。

针对开发人员超乎想象的便捷,点击按钮,打开报表设计器,仅仅2行代码:

  1:         private void button1_Click(object sender, EventArgs e)
  2:         {
  3:             FarPoint.Win.Spread.Design.FpSpreadDesigner design = new FarPoint.Win.Spread.Design.FpSpreadDesigner();
  4:             design.ShowDialog(this.fpSpread1);
  5:         }

 

Step 2: 财务报表操作

 

为表��增加一个上下文菜单, 通过ContextMenu属性可创建一个ContextMenu, 通过右键菜单可实现很多实用的功能场景,详情见下截图: 

Spread-财务报表

 

支持自定义丰富的单元格类型。通过用Spread提供的单元格类型或定制自己的类型,确定在一个单元格中可以输入什么样的数据、避免程序员不必要的检查和验证,并为用户提供一种自然的输入数据的方式

  • 货币
  • 日期-时间型
  • 普通型
  • Mask型
  • 数值型
  • 百分比型
  • 常规表达式型
  • 文本型
  • 开关型
  • 按钮型
  • 复选框型
  • 组合框型
  • 超链接型
  • 图形型
  • 多选项型
  • 进度指示条形
  • Rich Text型
  • 滑块型

注:为了快速呈现原型系统,这里仅列举出了5种数据类型。

改变数据类型代码示例:

  1:  private void SetCellType(string menuText)
  2:         {
  3: 
  4:             BaseCellType baseType = null;
  5:             switch (menuText)
  6:             {
  7:                 case "单元格类型":
  8:                     break;
  9:                 case "数字类型":
 10:                     {
 11:                         FarPoint.Win.Spread.CellType.NumberCellType objNumCell = new FarPoint.Win.Spread.CellType.NumberCellType();
 12:                         objNumCell.DecimalPlaces = 0;
 13:                         objNumCell.MinimumValue = 1;
 14:                         objNumCell.MaximumValue = 9999;
 15:                         objNumCell.ShowSeparator = false;
 16:                         baseType = objNumCell;
 17:                     }
 18:                     break;
 19:                 case "日期类型":
 20:                     {
 21:                         FarPoint.Win.Spread.CellType.DateTimeCellType objDateCell = new FarPoint.Win.Spread.CellType.DateTimeCellType();
 22:                         objDateCell.DateTimeFormat = FarPoint.Win.Spread.CellType.DateTimeFormat.ShortDate;
 23:                         baseType = objDateCell;
 24:                     }
 25:                     break;
 26:                 case "文本类型":
 27:                     {
 28:                         FarPoint.Win.Spread.CellType.TextCellType objTextCell = new FarPoint.Win.Spread.CellType.TextCellType();
 29:                         objTextCell.MaxLength = 100;
 30:                         baseType = objTextCell;
 31:                     }
 32:                     break;
 33:                 case "单选框类型":
 34:                     {
 35:                         FarPoint.Win.Spread.CellType.CheckBoxCellType objCheckCell = new FarPoint.Win.Spread.CellType.CheckBoxCellType();
 36:                         objCheckCell.ThreeState = false;
 37:                         baseType = objCheckCell;
 38:                     }
 39:                     break;
 40:                 case "货币类型":
 41:                     {
 42:                         FarPoint.Win.Spread.CellType.CurrencyCellType objCurrCell = new FarPoint.Win.Spread.CellType.CurrencyCellType();
 43:                         objCurrCell.LeadingZero = FarPoint.Win.Spread.CellType.LeadingZero.Yes;
 44:                         objCurrCell.NegativeRed = true;
 45:                         objCurrCell.FixedPoint = true;
 46:                         baseType = objCurrCell;
 47:                     }
 48:                     break;
 49:                 default:
 50:                     break;
 51:             }
 52: 
 53: 
 54:             if (baseType != null)
 55:             {
 56:                 fpSpread1.ActiveSheet.ActiveCell.CellType = baseType;
 57:             }
 58:         }

 

Step 3: 2D图表呈现

 

Spread支持85种丰富多彩的图表效果。可以在Spread设计器中基于工作表的数据直接生成图表,操作简单。同时,软件人员还可以在Visual Studio设计环境中定制图表的所有元素,包括标题、序列、轴、样式、图例等。

spread-Chart

 

图表的生成有2种途径

方法一:通过Spread设计器,类似Excel插入图表功能,非常易上手

方法二:通过代码实现,仅需要2步
         1 选择数据区域Range
         2 插入指定类型的图表:起始x、y坐标,宽度和高度

图表代码生成代码示例:

  1:             FarPoint.Win.Spread.Model.CellRange range = new CellRange(38, 2, 5, 4);
  2:             fpSpread1.Sheets[0].AddChart(range, typeof(BarSeries), 600, 300, 0, 0, ChartViewType.View2D, true);
  3: 
  4:             fpSpread1.Sheets[0].AddChart(range, typeof(FarPoint.Win.Chart.XYLineSeries), 600, 300, 0, 350, ChartViewType.View2D, true);
  5: 

 

Step 4: Excel数据导入

在数据处理系统中,有相当大的一块是做数据采集的,除了固定格式、海量数据可以通过采集系统程序采集外,其他配置数据、工程数据大多需要人工录入系统,但是手工一条一条录入有2点门槛:

  • 系统数据录入权限:数据系统对数据来源要求安全、质量很高,故录入数据权限不是100%开放所有用户
  • 手工录入数据效率低

故业内默认的行规是:批量数据录入是采用Excel模板,通过系统提供的Excel导入功能实现批量数据录入。

spread_excel_import

Spread会独立安装Excel文件格式的输入输出引擎,在没有安装Excel的环境中也可以进行Excel文件格式的输入输出,开发时设计的图表、图形、图像等都会作为对象输出到Excel文件中。Spread提供多种版本的Excel和多种文件类型的导入导出服务,包括Excel文件(XLS、XLSX)、档案文件(CSV)和文本文件(TXT)。

导入文件类型:

  • Spread XML 文件
  • Excel(.xls)文件
  • Spread 文件
  • 文本文件
    Excel数据导入有2个系统分界线:
    1 Excel文件到内存: 复杂度大、数据校验、Excel文件格式不同等等,难度较大。 约占开发工作量的60%
    2 内存到业务数据库:一旦到内存中,对开发者来说就如鱼得水了。约占开发工作量的30%~40%
    本文所说的Spread实现的数据导入,能够实现Excel文件到内存,也就是Excel数据预览功能,后续实现导入的业务逻辑代码,依据不同行业库表规则,写SQL实现insert即可。
    代码就一行:
  1:             this.fpSpread1.OpenExcel(ExcelFullPath);
  2: 

 

Step 5: 信息查询表单

复杂数据录入界面,通过Spread设计器实现复杂商业文档的录入界面,比如复杂的订单、发票、保单、报税表等。本文模拟量一个查询条件的查找表单,其中用到了本周新介绍的《Spread 7 for WinForms 新增的GcTextBoxCellType (水印、自动换行、自动大写、长度限制等)》单元格类型,非常实用。

spread_dataInput

 

表单是通过Spread 设计器设计好:背景、颜色、单元格类型、图片、按钮等等。然后保存为XML格式,在程序中通过两行代码加载实现的:

  1:    string fullPath = AppDomain.CurrentDomain.BaseDirectory + "..\\..\\ChartSpread.xml";
  2:    this.fpSpread1.Open(fullPath);

 

为了实现按回车进行查询功能,自定义了一个Action:

  1:     public class ClickButtonAction : FarPoint.Win.Spread.Action
  2:     {
  3:         public DataInputSpread mChartSpread;
  4:         public override void PerformAction(object source)
  5:         {
  6:             if (source is SpreadView)
  7:             {
  8:                 SpreadView spreadView = (SpreadView)source;
  9:                 mChartSpread.fpSpread1_ButtonClicked(spreadView, null);
 10:             }
 11:         }
 12:     }
 13: 
 14:             this.fpSpread1.ButtonClicked += fpSpread1_ButtonClicked;
 15: 
 16:             InputMap im = fpSpread1.GetInputMap(InputMapMode.WhenFocused);
 17:             ActionMap am = fpSpread1.GetActionMap();
 18:             im.Put(new Keystroke(Keys.Enter, Keys.None), "ClickButtonAction");
 19:             am.Put("ClickButtonAction", new ClickButtonAction() { mChartSpread = this });
 20: 
 21:         public void fpSpread1_ButtonClicked(object sender, EditorNotifyEventArgs e)
 22:         {
 23:             FarPoint.Win.Spread.SheetView sheet1;
 24:             if (sender is FarPoint.Win.Spread.FpSpread)
 25:             {
 26:                 sheet1 = (sender as FarPoint.Win.Spread.FpSpread).Sheets[1];
 27:             }
 28:             else
 29:             {
 30:                 sheet1 = (sender as FarPoint.Win.Spread.SpreadView).Sheets[1];
 31:             }
 32: 
 33:             string name = sheet1.Cells["name"].Text;
 34:             string phone = sheet1.Cells["phone"].Text;
 35:             string date = sheet1.Cells["date"].Text;
 36:             string sex = sheet1.Cells["sex"].Text;
 37: 
 38:             string msg = string.Format("搜索内容  姓名:{0}, 电话:{1}, 日期: {2}, 性别: {3}", name, phone, date, sex);
 39:             if (e != null)
 40:             {
 41:                 msg = string.Format("{0}, row:{1}, col:{2}", msg, e.Row, e.Column);
 42:             }
 43:             MessageBox.Show(msg);
 44:         }

 

 

代码下载: