项目背景

几年前参与了一个面向学校的人事管理软件的开发,基于WinForm平台。今天主要想谈一谈其中关于控件的使用经验。这个项目我们大量使用了第三方控件。由于这个产品的生命周期很长,我们在设计时要考虑表现层可能会有不同的形式,比如现在是WinForm以后可能会是WPF或者Web。另外也要考虑控件版本升级对产品的影响降到最低。

设计

基于上面的想法,我们通过两点来解决这些问题。MVP模式+控件封装,可以开发出更具弹性的View层。它能更有效的应对UI变化,包括控件升级这种小的UI变化,甚至是平台迁移等这种大的UI变化。

MVP(Model-View-Presenter)模式主要是为了表现层解耦,如果表现层的职责不单一,那么有控件升级或者UI层使用新的平台时花费的成本就会很高。使用MVC之后只有View层和控件相关,Presenter层实现UI逻辑。当View层变化时(控件升级或者新的UI形式),Presenter层、Model层都会被重用。

控件封装可以以一种统一的方式使用控件。所有使用到的控件全部封装即使是.Net控件也进行封装,不允许使用任何原生控件,只能使用封装后的控件。我们对控件的进行深度封装,将很多功能在控件中实现。

控件封装经验

我们以表格功能为例来介绍我们如何进行控件封装。在我们项目中对表格功能的要求非常高,一方面功能要非常强大,而且具有很强的定制开发能力,另一方面要求表格控件具有良好的性能。下面通过几个UI了解我们对表格的要求。

图1

图2

图3

图1和图2展示的是职员一览画面中,我们不仅仅加载出了职员信息,而且加载了职员的照片,需要一次性从数据库中加载几千张职员照片,对表格的性能要求很高。

图3展示以时间轴方式显示的职员状态。点击放大、缩小按钮,时间刻度的粒度也会发生变化,并重新刷新数据。

通过以上的两个示例可以看出我们对表格的性能和扩展性要求很高。我们综合对比了Spread,FlexGrid,MutilRow这几种表格控件,最终我们选择了FlexGrid控件。

FlexGrid控件封装

图4

图4是我们基于FlexGrid进行了深度封装的类图。在项目中不允许直接使用FlexGrid,只能使用我们封装后的JijiEditGrid等控件。我们以JijiBaseGrid为例来看看我们是如何进行封装。

下面节选了我们JijBaseGrid中的一些功能。

功能

描述

处理

Option机制

记忆列宽、字段顺序等

方法:LoadOption、SaveOption

列头菜单

字段显示/隐藏

属性:NeedHeaderMenu(设计时不可用)

统一管理颜色

Grid的配色是否随着Form走

属性:IsColorManaged(设计时可用)

接口:IColorControl

拷贝到剪贴板

根据Option进行特殊处理,分隔符、日期格式等

方法:CopyGridRangeToClip(RealText realText)

事件:public event EventHandler DataCopy = delegate { };

特殊键

F9:自动调整列宽

Ctrl+A:全选

Ctrl+C:复制

Delete:删除

PageDown:数据不满一页,PageDown按下时,跳转到最后一行

事件处理函数:override void OnKeyDown

我们仅仅选择“特殊键”这个功能,看看在OnKeyDown中的处理。这里主要处理各种特殊按钮,比如F9等。

        /// <summary>
/// Grid的按键押下事件
/// </summary>
/// <param name="e">参数</param>
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e); // 记录Control键是否按下
this.controlDown = e.Control; switch (e.KeyCode)
{
case Keys.F9:
if (this.CanF9)
{
// 列宽自动调整
Color oldColor = this.BackColor;
this.AutoSizeCols();
this.BackColor = oldColor;
}
break; case Keys.Delete:
if (this.CanDeleteRow())
{
// 处理行删除事件
this.RowDelete(this, new EventArgs());
}
else if (this.CanDeleteCellRange())
{
// 处理Cell范围选中删除事件
this.CellRangeDelete(this, new EventArgs());
}
break; case Keys.A:
if (e.Control)
{
// ctrl + A鍵的操作(全選)
int rowCount = this.GetRowCount();
if (rowCount > this.Rows.Fixed)
{
this.isControlA = true; this.Select(this.Rows.Fixed, this.Cols.Fixed, false);
this.Select(this.Rows.Fixed, this.Cols.Fixed, rowCount, this.Cols.Count - , false); this.isControlA = false;
}
}
break; case Keys.C:
if (e.Control && this.AllowCopy && this.DataCopy != null && this.DataCopy.Target != null)
{
// ctrl + C鍵的操作(復制)
this.DataCopy(this, new EventArgs());
}
break; case Keys.PageDown:
// 特殊处理数据不满一页,PageDown按下时,跳转到最后一行
this.DoPageDownEvent();
break;
}
}

默认的FlexGrid是没有这些功能的,我们重写OnKeyDown方法。根据自己的需求增加对各种特殊键的处理。

通过对控件进行全面的封装,当有新的需求或者有需求变更时和控件相关的功能我们只需在封装的控件中进行修改即可。

控件使用经验-MVP模式+控件封装的更多相关文章

  1. zw版【转发·台湾nvp系列Delphi例程】.NET调用HALCON COM控件内存释放模式

    zw版[转发·台湾nvp系列Delphi例程].NET调用HALCON COM控件内存释放模式 ------------------------------------方法一 :Imports Sys ...

  2. .net_DevExpress控件使用经验总结

    (转)DevExpress控件使用经验总结DevExpress是一个比较有名的界面控件套件,提供了一系列的界面控件套件的DotNet界面控件.本文主要介绍我在使用DevExpress控件过程中,遇到或 ...

  3. DevExpress控件使用经验总结- GridView列表行号显示操作

    DevExpress是一个比较有名的界面控件套件,提供了一系列的界面控件套件的DotNet界面控件.本文主要介绍我在使用DevExpress控件过程中,遇到或者发现的一些问题解决方案,或者也可以所示一 ...

  4. 【完全开源】百度地图Web service API C#.NET版,带地图显示控件、导航控件、POI查找控件

    目录 概述 功能 如何使用 参考帮助 概述 源代码主要包含三个项目,BMap.NET.BMap.NET.WindowsForm以及BMap.NET.WinformDemo. BMap.NET 对百度地 ...

  5. 带着问题写React Native原生控件--Android视频直播控件

    最近在做的采用React Native项目有一个需求,视频直播与直播流播放同一个布局中,带着问题去思考如何实现,能更容易找到问题关键点,下面分析这个控件解决方法: 现在条件:视频播放控件(开源的ijk ...

  6. 【转】【完全开源】百度地图Web service API C#.NET版,带地图显示控件、导航控件、POI查找控件

    [转][完全开源]百度地图Web service API C#.NET版,带地图显示控件.导航控件.POI查找控件 目录 概述 功能 如何使用 参考帮助 概述 源代码主要包含三个项目,BMap.NET ...

  7. MFC编程入门之二十五(常用控件:组合框控件ComboBox)

    上一节讲了列表框控件ListBox的使用,本节主要讲解组合框控件Combo Box.组合框同样相当常见,例如,在Windows系统的控制面板上设置语言或位置时,有很多选项,用来进行选择的控件就是组合框 ...

  8. 利用Aspose.Word控件和Aspose.Cell控件,实现Word文档和Excel文档的模板化导出

    我们知道,一般都导出的Word文档或者Excel文档,基本上分为两类,一类是动态生成全部文档的内容方式,一种是基于固定模板化的内容输出,后者在很多场合用的比较多,这也是企业报表规范化的一个体现. 我的 ...

  9. Delphi下使用Oracle Access控件组下TOraSession控件链接

    Delphi下使用Oracle Access控件组下TOraSession控件链接数据库,使用  orsn1.Options.Direct:=true;  orsn1.Server:=IP:Port: ...

随机推荐

  1. nodejs获取客户端IP Address

    在网上看见很多问node.js如何获取客户端IP,所以记录下来,以供大家参考. function getClientIp(req) { return req.headers['x-forwarded- ...

  2. Spring-Context之九:在bean定义中使用继承

    定义bean时有个abstract属性,可以设置为true或false,默认为false. 1 2 3 4 <bean id="animal" class="Ani ...

  3. 阿里巴巴B2B搜索学习

    1.搜索业务 主搜索:商品搜索.商家搜索.采购搜索.app搜索 行业搜索:淘货源.淘工厂.聚好货.主题市场.品牌馆等 2.优势 由于用户多,需求强烈,收益大,所以功能.场景.架构做到极致高效. 代码复 ...

  4. AI-随机迷宫&迷宫求解

    本文记录了,人工智能中简单的搜索策略中的路径搜索策略中的A*算法,来实现迷宫寻路的问题.(这只是一次本人的课外作业) 完整的程序源码已经发送到我的Git.这里只记录了我的思路和感想以及收获. 产生随机 ...

  5. java.sql.SQLException: JZ00L

    出现, java.sql.SQLException: JZ00L: 登录失败.检查与此异常现象有关的 SQL 警告以获得失败原因. at com.sybase.jdbc3.jdbc.ErrorMess ...

  6. 缓存篇~第八回 Redis实现基于方法签名的数据集缓存~续(优化缓存中的key)

    返回目录 上一讲主要是说如何将数据集存储到redis服务器里,而今天主要说的是缓存里的键名,我们习惯叫它key. redis或者其它缓存组件实现的存储机制里,它将很多方法对应的数据集存储在一个公共的空 ...

  7. Atitit   图像处理 平滑 也称 模糊, 归一化块滤波、高斯滤波、中值滤波、双边滤波)

    Atitit   图像处理 平滑 也称 模糊, 归一化块滤波.高斯滤波.中值滤波.双边滤波) 是一项简单且使用频率很高的图像处理方法 用途 去噪 去雾 各种线性滤波器对图像进行平滑处理,相关OpenC ...

  8. [转] 移动前端不得不了解的HTML5 head 头标签

    HTML的头部内容特别多,有针对SEO的头部信息,也有针对移动设备的头部信息.而且各个浏览器内核以及各个国内浏览器厂商都有些自己的标签元 素,有很多差异性.移动端的工作已经越来越成为前端工作的重要内容 ...

  9. CentOS 下 LVS集群( 可能更新 )

    lvs-nat模型构建 假设测试环境:使用IP172.16.16.16. 需要A.B俩台Centos6.5虚拟机.提前关闭selinux 两台真实服务器的IP分别是192.168.1.1.192.16 ...

  10. 快速入门系列--MySQL

    一直说要好好复习一下Mysql都木有时间,终于赶上最近新购买了阿里云,决定使用CentOS去试试.NET Core等相关的开发,于是决定好好的回顾下这部分知识,由于Mysql的数据库引擎是插件式的,对 ...