何为扩展,顾名思义,就是在原有控件属性、事件的基础上拓展自己需要或实用的属性、事件等等。或者可以理解为,现有的控件已经不能完全满足我(的需求)了。好的扩展会使控件更加完善,实用,好用。不好的扩展,说白了就是画蛇添足!好了,跟着博主一起玩转控件吧,看看您在实际项目运用中是否也曾几何时遇到过这样的困惑。

本篇拿一个简单的Dev控件为例,件如其名——SimpleButton,一个成熟的软件,一定会考虑到所有人的操作习惯以及简洁舒适的界面。做人如是,控件如是。

本篇缘起于博主最近削尖脑袋,硬着头皮看英文文档。那家伙把我读的,那场面,那气势,真是锣鼓喧天鞭炮起,红旗招展,文山文海... 大部分它认识我,我不认识它。最后还得靠多年酝酿的Google大法才能拨开云雾见青天。偶然间联想到最近预热的《手撕ERP》(FuckingERP)之控件系列,公众号私信里面有很多国外的朋友,拿到源码,信誓旦旦的按下F5傻眼了。全是中文字,而且有的还乱码。

  因此,鉴于此,从本篇起,后续所有控件系列都会扩展一个多语言的属性功能(俗称国际化)。多语言功能有很多实现方式,博主之前也实践过很多方式,比如资源文件处理、展示界面前调用Google翻译后赋值等等,这些方式有利有弊,本篇博主将采用另外一种方式来实现多语言-数据库存储,键值对取值的方式。巴拉巴拉巴拉.....

扯远了扯远了,回归主题,还是来看看博主是怎么扩展按钮的吧!

Talk is Cheap,Show me the Code!

首先,新建一个用户控件,并让其继承Dev原始控件SimpleButton

public partial class KzxSimpleButton : SimpleButton, ILayoutControl

  后面的ILayoutControl接口,是我用来定义要实现的属性和事件的,部分代码如下:

/// <summary>
/// 没有多语言的情况下的默认显示标题
/// </summary>
string DesigeCaption { get; set; }
/// <summary>
/// 设计时的可用性
/// </summary>
bool DesigeEnabled { get; set; }
/// <summary>
/// 设计时可见性
/// </summary>
bool DesigeVisible { get; set; }
/// <summary>
/// 控件的唯一标识
/// </summary>
string Key { get; set; }
/// <summary>
/// 布局列号
/// </summary>
int LayoutColumn { get; set; }
/// <summary>
/// 布局跨的列数
/// </summary>
int LayoutColumnSpan { get; set; }
/// <summary>
/// 布局行号
/// </summary>
int LayoutRow { get; set; }
/// <summary>
/// 布局跨的行数
/// </summary>
int LayoutRowSpan { get; set; }
/// <summary>
/// 多语言环境下显示文本的对应标识
/// </summary>
string MessageCode { get; set; } /// <summary>
/// 事件插件信息表
/// </summary>
DataTable PluginInfoTable { get; set; } /// <summary>
/// 事件列表
/// </summary>
string EventList { get; set; } /// <summary>
/// 提示信息
/// </summary>
string ToolTipText { get; set; } /// <summary>
/// 提示多语言标识
/// </summary>
string ToolTipMessageCode { get; set; } /// <summary>
/// 绑定事件
/// </summary>
/// <param name="valueControl">控件</param>
/// <param name="eventInfoTable">事件信息表</param>
void BindingEvent(Control valueControl, DataTable eventInfoTable); /// <summary>
/// 设置布局
/// </summary>
void SetLayout(); /// <summary>
/// 控件被加载后调用的方法
/// 此方法在控件还原后被窗口调用
/// </summary>
void KzxControlLoaded(); /// <summary>
/// 控件事件
/// </summary>
event KzxControlOperateEventHandler KzxControlOperate;
/// <summary>
/// 获取多语言文本事件
/// </summary>
event KzxGetLanguageEventHandler KzxGetLanguage;

  然后在刚刚新建的用户控件实现这个接口,部分代码如下:

#region 布局属性
private int _LayoutRow = ;
/// <summary>
/// 布局行号
/// </summary>
[Category("布局"), Description("LayoutRow,布局行号"), Browsable(false)]
[McDisplayName("LayoutRow")]
public int LayoutRow
{
get
{
if (this.DesignMode == true)
{
TableLayoutPanel panel = this.Parent as TableLayoutPanel;
if (panel != null)
{
this._LayoutRow = panel.GetRow(this);
}
}
return this._LayoutRow;
}
set
{
this._LayoutRow = value;
if (this.DesignMode == true)
{
TableLayoutPanel panel = this.Parent as TableLayoutPanel;
if (panel != null)
{
panel.SetRow(this, value);
}
}
}
} private int _LayoutRowSpan = ;
/// <summary>
/// 布局跨的行数
/// </summary>
[Category("布局"), Description("LayoutRowSpan,布局跨的行数"), Browsable(false)]
[McDisplayName("LayoutRowSpan")]
public int LayoutRowSpan
{
get
{
TableLayoutPanel panel = this.Parent as TableLayoutPanel;
if (panel != null)
{
panel.SetRowSpan(this, this._LayoutRowSpan);
}
return this._LayoutRowSpan;
}
set
{
this._LayoutRowSpan = value;
TableLayoutPanel panel = this.Parent as TableLayoutPanel;
if (panel != null)
{
panel.SetRowSpan(this, value);
}
}
} private int _LayoutColumn = ;
/// <summary>
/// 布局列号
/// </summary>
[Category("布局"), Description("LayoutColumn,布局列号"), Browsable(false)]
[McDisplayName("LayoutColumn")]
public int LayoutColumn
{
get
{
if (this.DesignMode == true)
{
TableLayoutPanel panel = this.Parent as TableLayoutPanel;
if (panel != null)
{
this._LayoutColumn = panel.GetColumn(this);
}
}
return this._LayoutColumn;
}
set
{
this._LayoutColumn = value;
if (this.DesignMode == true)
{
TableLayoutPanel panel = this.Parent as TableLayoutPanel;
if (panel != null)
{
panel.SetColumn(this, value);
}
}
}
} private int _LayoutColumnSpan = ;
/// <summary>
/// 布局跨的列数
/// </summary>
[Category("布局"), Description("LayoutColumnSpan,布局跨的列数"), Browsable(false)]
[McDisplayName("LayoutColumnSpan")]
public int LayoutColumnSpan
{
get
{
TableLayoutPanel panel = this.Parent as TableLayoutPanel;
if (panel != null)
{
panel.SetColumnSpan(this, this._LayoutColumnSpan);
}
return this._LayoutColumnSpan;
}
set
{
this._LayoutColumnSpan = value;
TableLayoutPanel panel = this.Parent as TableLayoutPanel;
if (panel != null)
{
panel.SetColumnSpan(this, value);
}
}
} #endregion

  为了效果明显点,博主就拿ToolTip来举例,以及部分事件代码如下:

private string _MessageCode = "";
/// <summary>
/// 多语言环境下显示文本的对应标识
/// </summary>
[Category("多语言"), Description("MessageCode,多语言环境下显示文本的对应标识"), Browsable(true)]
[McDisplayName("MessageCode")]
public virtual string MessageCode
{
get
{
return this._MessageCode;
}
set
{
this._MessageCode = value;
}
} private string _DesigeCaption = string.Empty;
/// <summary>
/// 没有多语言的情况下的默认显示标题
/// </summary>
[Category("多语言"), Description("DesigeCaption,没有多语言的情况下的默认显示标题"), Browsable(true)]
[McDisplayName("DesigeCaption")]
public virtual string DesigeCaption
{
get
{
return this.Text.Trim();
}
set
{
this.Text = value;
}
}

  拿ToolTip举个例子

#region 方法
private DataTable _PluginInfoTable = KzxBaseControl.CreatePluginDataTable();
[Category("自定义"), Description("PluginInfoTable,事件插件信息表"), Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[McDisplayName("PluginInfoTable")]
public DataTable PluginInfoTable
{
get
{
return this._PluginInfoTable;
}
set
{
this._PluginInfoTable = value;
BindingEvent(this, this._PluginInfoTable);
}
} private string _ToolTipText = string.Empty;
/// <summary>
/// 提示信息
/// </summary>
[Category("汽泡提示"), Description("ToolTipText,提示信息"), Browsable(true)]
[McDisplayName("ToolTipText")]
public virtual string ToolTipText
{
get
{
return this._ToolTipText;
}
set
{
this._ToolTipText = value;
}
} private string _ToolTipMessageCode = string.Empty;
/// <summary>
/// 提示多语言标识
/// </summary>
[Category("汽泡提示"), Description("ToolTipMessageCode,提示信息多语言标识"), Browsable(true)]
[McDisplayName("ToolTipMessageCode")]
public virtual string ToolTipMessageCode
{
get
{
return this._ToolTipMessageCode;
}
set
{
this._ToolTipMessageCode = value;
}
} private Color _LabelForeColor = Color.Black;
/// <summary>
/// 标签字体颜色
/// </summary>
[Category("外观"), Description("LabelForeColor,标签字体颜色"), Browsable(true)]
[McDisplayName("LabelForeColor")]
public Color LabelForeColor
{
get
{
return this.ForeColor;
}
set
{
this._LabelForeColor = value;
this.ForeColor = value;
}
} /// <summary>
/// 控钮类型
/// </summary>
[Category("外观"), Description("YZButtonStyle,控钮类型"), Browsable(true)]
[McDisplayName("YZButtonStyle")]
public DevExpress.XtraEditors.Controls.BorderStyles YZButtonStyle
{
get
{
return this.ButtonStyle;
}
set
{
this.ButtonStyle = value;
}
} #endregion

  代码比较简单,关键属性和事件也已经添加了详细备注,就不一一解释了。用户控件创建好后,我们就可以直接实用拖控件大法了。

  效果如下:

  实现控件按钮,鼠标悬浮提示框(ToolTip)插件代码也比较简单,具体如下:

     其中ssLoadMsgOrDefault方法,就是博文开头提到的,数据库存储-键值对取值的方法,具体如下:

/// <summary>
/// 根据Msg_ID取相应语言描述,获取为空时显示 emptyDisplayMsg
/// </summary>
/// <param name="msgID"></param>
/// <param name="emptyDisplayMsg"></param>
/// <returns></returns>
public static string ssLoadMsgOrDefault(string msgID, string emptyDisplayMsg)
{
if (string.IsNullOrWhiteSpace(msgID))
return emptyDisplayMsg; var msgText = string.Empty;
if (SysVar.LanguageList.ContainsKey(msgID))
msgText = SysVar.LanguageList[msgID]; if (string.IsNullOrWhiteSpace(msgText))
msgText = emptyDisplayMsg; return msgText;
}

  为了方便处理多语言,博主还写了个小软件,用来存储或生成多语言对应关系,这个后续会给大家介绍,好了,让我们F5来看看具体效果:

  最后,由于后续所有重写/重绘控件都在同一个项目使用,而且Dev系统引用文件较多,压缩后源码文件仍然很大,如果有需要源码的朋友,可以微信公众号联系博主,源码可以免费赠予~!有疑问的也可以CALL我一起探讨,最最后,如果觉得本篇博文对您或者身边朋友有帮助的,麻烦点个关注!赠人玫瑰,手留余香,您的支持就是我写作最大的动力,感谢您的关注,期待和您一起探讨!再会!

玩转控件:扩展Dev中SimpleButton的更多相关文章

  1. 玩转控件:对Dev中GridControl控件的封装和扩展

    又是一年清明节至,细雨绵绵犹如泪光,树叶随风摆动.... 转眼间,一年又过去了三分之一,疫情的严峻让不少企业就跟清明时节的树叶一样,摇摇欲坠.裁员的裁员,降薪的降薪,996的996~~说起来都是泪,以 ...

  2. 玩转控件:对Dev的GridControl控件扩展

    缘由 一切实现来源于需求,目的在于不盲目造轮子,有小伙伴儿在看了<玩转控件:对Dev中GridControl控件的封装和扩展>文章后,私信作者说,因公司业务逻辑比较复杂,展示字段比较多,尤 ...

  3. 玩转控件:封装Dev的SearchLookupEdit

    鸣谢 随着前面几个章节对控件封装与扩展的分享,不少小伙伴儿们在作者公众号上反馈,并联系作者,表示通过这些系列和源码能学到不少细节上的东西,并运用到了自己的实际项目当中,也有不少伙伴儿反馈更好更优的处理 ...

  4. 玩转控件:封装Dev的LabelControl和TextEdit

    俗话说的好:"工欲善其事必先利其器",作为软件攻城狮也是同样道理,攻城狮开发的软件目的是简化客户的操作,让客户动动手指就可以完成很多事情,减少人力成本.这也是系统/软件存在的目的. ...

  5. 玩转控件:Fucking ERP之流程图

    前言 首先,跟守护在作者公众号和私信作者催更的朋友们道个歉.疫情的原因,公司从年初到现在一直处于996+的高压模式,导致公众号更新频率较低.而且作者每更新一篇原创公众号,既要对自己沉淀知识负责,也要对 ...

  6. 玩转控件:重写/重绘Dev中MessageBox弹窗控件

    很久没有更新博客了,本想着直接发一篇<手撕ERP>系列,从控件重写.重绘,到框架搭建,再到部分模块实现+业务的.但是每次动手的时候,都觉得难以下手.直接从数据库设计开始吧,模块设计还没定下 ...

  7. 玩转控件:重绘DEVEXPRESS中DateEdit控件 —— 让DateEdit支持只选择年月 (提供源码下载)

      前言 上一篇博文<玩转控件:重绘ComboBox —— 让ComboBox多列显示>中,根据大家的回馈,ComboBox已经支持筛选了,更新见博文最后最后最后面.   奇葩 这两天遇到 ...

  8. 给easyui datebox时间框控件扩展一个清空的实例

    给easyui datebox扩展一个清空的实例 步骤一:拓展插件 /** * 给时间框控件扩展一个清除的按钮 */ $.fn.datebox.defaults.cleanText = '清空'; ( ...

  9. WPF开源控件扩展库 - MaterialDesignExtensions

    Material Design Extensions 在WPF开源控件库 Material Design in XAML Toolkit(本站介绍:链接)的基础上进行了控件扩展和特性新增.本开源项目中 ...

随机推荐

  1. PowerDesigner的文章

    来自iteye的PowerDesigner的相关文章,写的不错,这里引用一下 PD12 建模工具的使用 博客分类: PowerDesigner .net http://jpkc.zjbti.net.c ...

  2. 关于KMP算法的重大发现

    之前写KMP模板的时候,nx[i]代表最大的一个x,使s[1,x-1]是s[1,i-1]的后缀.(方法1) 然而网上还有另一种方法求nx数组,nx[i]表示最大的一个x,使s[1,x]是s[1,i]的 ...

  3. npm安装依赖太慢问题

    执行 npm install 会发现很慢,可以在安装时手动指定从哪个镜像服务器获取资源,我使用的是阿里巴巴在国内的镜像服务器. 命令如下: npm install --registry=https:/ ...

  4. tomcat——nginx负载均衡

    Tomcat一般应用在这种小型系统中应用非常广泛,是开发调试jsp的首先应用.Tomcat和其他web软甲一样具有解析HTML语言的功能,但是处理效率远不及Apacge和Nginx,所以Tomcat一 ...

  5. 来自ebay内部的「软件测试」学习资料,覆盖GUI、API自动化、代码级测试及性能测试等,Python等,拿走不谢!...

    在软件测试领域从业蛮久了,常有人会问我: 刚入测试一年,很迷茫,觉得没啥好做的-- 测试在公司真的不受重视,我是不是去转型做开发会更好?  资深的测试架构师的发展路径是怎么样的?我平时该怎么学习? 我 ...

  6. Jenkins+Git+Fastlane+Fir CI集成

    上一篇有讲关于fastlane自动化部署,本篇将会着重讲关于fastlane的实际应用. 目标: 利用自动化jenkins打包工具,自动拉取git仓库代码 不需要通过手动检查修改xcode中项目配置修 ...

  7. 【基础篇】hexo博客搭建教程

    [基础篇]搭建hexo博客(一) 作者:Huanhao bilibili:Mrhuanhao 前言 你是否想拥有属于自己的博客?你是否无奈与自己不会写网站而烦恼? 不要担心,本系列教程将会实现你白嫖的 ...

  8. C++扬帆远航——2

    /* * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:test.cpp * 作者:常轩 * 完成日期:2016年3月6 ...

  9. webpack环境配置2

    1.webpack安装 Step 1: 首先安装Node.js, 在1中已经详细介绍了. Step2: 在Git或者cmd中输入下面这段代码, 通过全局先将webpack指令安装进电脑中npm ins ...

  10. Vue-API之全局配置

    API 全局配置 Vue.config 是一个对象,包含 Vue 的全局配置. 源码位置:util/config.js 搜索config 可以找到其源码地址,其中声明了config的类型和默认参数 下 ...