十八、【开源】EnterpriseFrameWork框架核心类库之Winform控制器
回《【开源】EnterpriseFrameWork框架系列文章索引》
EFW框架源代码下载:http://pan.baidu.com/s/1qWJjo3U
EFW框架中的WinController控制器可以说是整个Winform版中最具有价值的地方,能够熟练使用它的话,可以让你写得代码结构清晰不知多少倍,真正的做到了CS开发的界面层与逻辑层的完全隔离;更重要的是改变了你写界面代码的思维,让你一次性写出功能完善的代码,真的,传统的那种事件驱动的方式编码会让你的代码变得越来越臃肿,就算你懂得不断重构你的代码,也完全避免不了出现臃肿的情况;所以必须使用WinController控制器模式从源头彻底解决这种问题;
WinController控制器与界面不一定是一一对应的,一个控制器可以对应多个界面,当几个界面的操作十分密切时就可以用一个控制器来控制它们的行为;一个界面对应多个控制器这种方式最好不要这么做,这样会让你的程序变得复杂,也破坏了业务架构与框架之间的关系,参考第十一章《EnterpriseFrameWork框架的分层与系统业务的结合》。
本章主要内容通过解读框架源代码来学习WinController是怎么实现的,以及学习控制器这种设计模式;
本文要点:
1.如何使用Winform控制器
2.Winform控制器的设计思路
3.Winform控制器BaseController基类的实现代码
4.Winform控制器的自定义标签MenuAttribute和ViewAttribute
5.通过Winform控制器打开界面
Winform控制器源代码目录结构
EFW框架控制器设计图
1.如何使用Winform控制器
如上图,Books.Winform项目里的是界面文件,Books项目的是界面接口文件和控制器文件,frmBookManager对象继承IfrmBook接口,bookwinController对象依IfrmBook接口;
见上图,Books实例中保存数据功能代码调用流程,界面代码frmBookManager继承了IfrmBook接口的两个方法并实现,点击保存按钮,btnsave_Click事件内并不实现保存数据的代码而只是向控制器发送一个消息,指定需要调用的方法名称bookSave,程序开始执行控制器中的bookSave方法,利用接口属性frmBook.currBook从界面获取数据,并利用框架中的ORM保存到数据库;接着调用GetBooks方法将数据显示在界面上;GetBooks方法调用后台的IBookDao对象获取Book数据,再通过frmBook.loadbooks(dt)接口方法将数据绑定到界面控件gridBook上;
2.Winform控制器的设计思路
Winform控制器的设计思路有点类似Web系统中的MVC模式,控制器处理这后台数据对象与前台界面直接的交互,利用接口从界面获取数据,再传递给后台对象处理,处理完后再利用接口将数据传递给界面控件显示;整个交互的逻辑代码是在控制器中实现的,数据怎么从界面获取与数据怎么绑定到界面控件都是在前端界面接口中实现的,而数据怎么存储到数据库与怎么从数据库获取数据都是在后端Dao或ObjectModel中实现的,当然也可以在控制器中利用oleDb直接操作数据库,但好的程序结构还是放在Dao和ObjectModel中合适些;
Winform控制器必须继承框架中的BaseController对象,还有控制器类名上要指定菜单标签MenuAttribute和界面标签ViewAttribute,BaseController对象封装了控制器的一些处理功能,MenuAttribute和ViewAttribute一个对应系统的菜单名,一个决定控制器能操作的界面对象;
3.Winform控制器BaseController基类的实现代码
因为所有Winform控制器都必须继承BaseController基类,所以我们有必要先看一下BaseController基类的代码是怎么样的;
BaseController文件
/// <summary>
/// Winform控制器基类
/// </summary>
public abstract class BaseController : AbstractBusines
{
public AbstractDatabase oleDb
{
get
{
return _oleDb;
}
} public SysLoginRight GetSysLoginRight
{
get
{
if (EFWCoreLib.CoreFrame.Init.AppGlobal.cache.GetData("RoleUser") != null)
{
return (SysLoginRight)EFWCoreLib.CoreFrame.Init.AppGlobal.cache.GetData("RoleUser");
}
else
{
return new SysLoginRight();
}
}
} internal IBaseView _defaultView; public IBaseView DefaultView
{
get { return _defaultView; }
} private Dictionary<string, IBaseView> _iBaseView;
public Dictionary<string, IBaseView> iBaseView
{
get { return _iBaseView; }
set
{
_iBaseView = value;
foreach (KeyValuePair<string, IBaseView> val in _iBaseView)
{
//val.Value.ControllerEvent += new ControllerEventHandler(UI_ControllerEvent);
val.Value.InvokeController = new ControllerEventHandler(UI_ControllerEvent);
}
}
} public CloseTab closeTab; /// <summary>
/// 创建BaseController的实例
/// </summary>
public BaseController()
{ }
/// <summary>
/// 界面控制事件
/// </summary>
/// <param name="eventname">事件名称</param>
/// <param name="objs">参数数组</param>
/// <returns></returns>
public virtual object UI_ControllerEvent(string eventname, params object[] objs)
{
switch (eventname)
{
case "Close":
if (closeTab != null)
closeTab();
break;
case "this":
return this;
} MethodInfo meth = this.GetType().GetMethod(eventname);
if (meth != null)
{
MethodAttribute[] WinM = (MethodAttribute[])meth.GetCustomAttributes(typeof(MethodAttribute), true);
if (WinM.Length > )
{
if (WinM[].OpenDBKeys != null && WinM[].OpenDBKeys.ToString().Trim() != "")
{
List<string> dbkeys = WinM[].OpenDBKeys.Split(new char[] { ',' }).ToList();
this.BindMoreDb(oleDb, "default");
foreach (string dbkey in dbkeys)
{
EFWCoreLib.CoreFrame.DbProvider.AbstractDatabase _Rdb = EFWCoreLib.CoreFrame.DbProvider.FactoryDatabase.GetDatabase(dbkey);
_Rdb.WorkId = GetSysLoginRight.WorkId;
//创建数据库连接
this.BindMoreDb(_Rdb, dbkey);
}
}
}
return meth.Invoke(this, objs);
}
return null;
} /// <summary>
/// 初始化全局web服务参数对象
/// </summary>
public virtual void Init() { } public virtual IBaseView GetView(string frmName)
{
return iBaseView[frmName];
}
}
BaseController基类封装了控制器的四方面的功能:
1)数据库操作对象oleDb,这样我们可以直接在控制器方法内使用它执行SQL语句操作数据库
2)系统登录后的用户信息GetSysLoginRight,这样我们可以再控制器中很方便的使用当前登录的用户信息;
3)界面对象字典iBaseView,这属性与控制器上ViewAttribute标签配置相对应,可以从中取出配置的界面接口对象来操作界面;
4)处理界面请求控制器方法的功能UI_ControllerEvent,界面使用InvokeController向控制器发送消息,而怎么效应界面的消息在此方法中实现的,利用反射机制执行对应的控制器方法;
4.Winform控制器的自定义标签MenuAttribute和ViewAttribute
这里的设计是这样的,一个控制器可以配置多个MenuAttribute,那么系统可以挂多个菜单,而这几个菜单都是公用这一个控制器,同样一个控制器可以配置多个ViewAttribute,控制器就可以同时操作这些配置的界面;
MenuAttribute文件
[AttributeUsageAttribute(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public class MenuAttribute:Attribute
{ string _defaultName; /// <summary>
/// 菜单名称
/// </summary>
public string DefaultName
{
get { return _defaultName; }
set { _defaultName = value; }
} private string _defaultViewName;
/// <summary>
/// 菜单对应打开界面
/// </summary>
public string DefaultViewName
{
get { return _defaultViewName; }
set { _defaultViewName = value; }
} string _memo;
public string Memo
{
get { return _memo; }
set { _memo = value; }
} public MenuAttribute()
{
} public MenuAttribute(string defaultName,string memo)
{
this._defaultName = defaultName;
this._memo = memo;
}
}
ViewAttribute文件
[AttributeUsageAttribute(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class ViewAttribute:Attribute
{
private string _name;
/// <summary>
/// 界面名称
/// </summary>
public string Name
{
get { return _name; }
set { _name = value; }
} private bool _defaultShow;
public bool DefaultView
{
get { return _defaultShow; }
set { _defaultShow = value; }
} private Type _viewType;
/// <summary>
/// 界面对象类型
/// </summary>
public Type ViewType
{
get { return _viewType; }
set { _viewType = value; }
} private string _dllName;
/// <summary>
/// 界面存放的DLL
/// </summary>
public string DllName
{
get { return _dllName; }
set { _dllName = value; }
} private string _viewTypeName;
/// <summary>
/// 界面类型名称
/// </summary>
public string ViewTypeName
{
get { return _viewTypeName; }
set { _viewTypeName = value; }
} string _memo;
public string Memo
{
get { return _memo; }
set { _memo = value; }
}
}
5.通过Winform控制器打开界面
Winform系统打开一个界面是这样操作的,用户点击系统主界面上的菜单,框架就会调用WinformViewCreator对象来实例化控制器对象和实例化控制器配置的所有界面窗体对象,所以我们有必要看一下WinformViewCreator对象是怎么实现的;
WinformViewCreator文件
public override Object InstanceController(CloseTab close)
{
try
{ //加载类库
Assembly assembly = null;
assembly = Assembly.LoadFrom(AppGlobal.AppRootPath + "\\" + dllfile); //获得控制器类(型)
Type type = assembly.GetType(controllername, false, true); MenuAttribute[] menuAttribute = (MenuAttribute[])type.GetCustomAttributes(typeof(MenuAttribute), true);
ViewAttribute[] viewAttribute = (ViewAttribute[])type.GetCustomAttributes(typeof(ViewAttribute), true);
//ServiceAttribute[] serviceAttribute = (ServiceAttribute[])type.GetCustomAttributes(typeof(ServiceAttribute), true); if (menuAttribute.Length > )
{
Dictionary<string, IBaseView> viewDic = new Dictionary<string, IBaseView>();
//Dictionary<string, SoapHttpClientProtocol> serviceDic = new Dictionary<string, SoapHttpClientProtocol>();
BaseController controller = (BaseController)System.Activator.CreateInstance(type); EFWCoreLib.CoreFrame.DbProvider.AbstractDatabase Rdb = EFWCoreLib.CoreFrame.DbProvider.FactoryDatabase.GetDatabase();
Rdb.WorkId = controller.GetSysLoginRight.WorkId;
controller.BindDb(Rdb, AppGlobal.container); controller.closeTab = close;//关闭窗口 for (int index = ; index < viewAttribute.Length; index++)
{
if (viewAttribute[index].ViewType == null)
{
if (string.IsNullOrEmpty(viewAttribute[index].DllName))
{
continue;
}
Assembly _assembly = Assembly.LoadFrom(AppGlobal.AppRootPath + "\\" + viewAttribute[index].DllName);
viewAttribute[index].ViewType = _assembly.GetType(viewAttribute[index].ViewTypeName, false, true);
}
IBaseView view = (IBaseView)System.Activator.CreateInstance(viewAttribute[index].ViewType);
if (viewAttribute[index].DefaultView) controller._defaultView = view;
if (index == && viewAttribute.ToList().FindIndex(x => x.DefaultView == true) == -) controller._defaultView = view;
viewDic.Add(viewAttribute[index].ViewType.Name, view);
}
//for (int index = 0; index < serviceAttribute.Length; index++)
//{
// SoapHttpClientProtocol service = (SoapHttpClientProtocol)System.Activator.CreateInstance(serviceAttribute[index].ServiceType);
// serviceDic.Add(serviceAttribute[index].ServiceType.Name, service);
//} controller.iBaseView = viewDic;
//controller.service = serviceDic; controller.Init();//初始化
return controller;
} return null;
}
catch (Exception err)
{
throw err;
}
}
上面代码中有两点需要说明一下,首先根据菜单配置的控制器名称通过反射实例化控制器对象;
接着根据控制器的配置的ViewAttribute标签,实例化界面对接并添加到iBaseView属性中;
十八、【开源】EnterpriseFrameWork框架核心类库之Winform控制器的更多相关文章
- 十二、EnterpriseFrameWork框架核心类库之与EntLib结合
从本章开始对框架的讲叙开始进入核心类库的讲解,前面都是对框架外在功能讲解,让人有个整体的概念,知道包含哪些功能与对系统开发有什么帮助.以后多章都是讲解核心类库的,讲解的方式基本按照代码的目录结构,这样 ...
- 十七、EnterpriseFrameWork框架核心类库之Web控制器
回<[开源]EnterpriseFrameWork框架系列文章索引> EFW框架源代码下载:http://pan.baidu.com/s/1qWJjo3U EFW框架中的WebContro ...
- 十五、EnterpriseFrameWork框架核心类库之系统启动入口与初始化
本章内容是讲三种开发模式,web模式.Winform模式和Wcf模式的系统启动入口有什么区别,以及启动后系统初始化的内容:为什么要把这些单独提出来讲一章,因为我觉得本章非常重要,我们都知道程序中的ma ...
- 十四、EnterpriseFrameWork框架核心类库之简易ORM
在写本章前先去网上找了一下关于ORM的相关资料,以为本章做准备,发现很多东西今天才了解,所以在这里也对ORM做不了太深入的分析,但还是浅谈一下EFW框架中的设计的简易ORM:文中有一点讲得很有道理,D ...
- 十六、【适合中小企业的.Net轻量级开源框架】EnterpriseFrameWork框架核心类库之单点登录SSO
回<[开源]EnterpriseFrameWork框架系列文章索引> EFW框架源代码下载:http://pan.baidu.com/s/1qWJjo3U 单点登录(Single Sign ...
- 十九、【.Net开源】EFW框架核心类库之WCF控制器
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.1:http://pan.baidu.com/s/1qWJjo3U EFW框架实例源代码下载:http://pan.baid ...
- 十三、EnterpriseFrameWork框架核心类库之数据库操作(多数据库事务处理)
本章介绍框架中封装的数据库操作的一些功能,在实现的过程中费了不少心思,针对不同数据库的操作(SQLServer.Oracle.DB2)这方面还是比较简单的,用工厂模式就能很好解决,反而是在多数据库同时 ...
- 二十、【.Net开源】EFW框架核心类库之WebService服务
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.1:http://pan.baidu.com/s/1qWJjo3U EFW框架实例源代码下载:http://pan.baid ...
- 嵌入式Linux驱动笔记(十八)------浅析V4L2框架之ioctl【转】
转自:https://blog.csdn.net/Guet_Kite/article/details/78574781 权声明:本文为 风筝 博主原创文章,未经博主允许不得转载!!!!!!谢谢合作 h ...
随机推荐
- 开启Github之旅
在那个远古时代,我以为可以用GoogleCode干点事,结果啥也没干好.如今,Github已经成为了业界标杆,就连Google.微软.Facebook的开源项目都往Github搬.Github作为全球 ...
- MongoDB学习笔记——索引管理
索引 索引能够提升查询的效率.没有索引,MongoDB必须扫描集合中的所有文档,才能找到匹配查询语句的文档. 索引是一种特殊的数据结构,将一小块数据集保存为容易遍历的形式.索引能够存储某种特殊字段或字 ...
- GO語言基礎教程:流程控制
在開始一個新的章節之前先來回顧上一篇文章的部份,首先我們來看這段代碼: package main import ( "fmt" ) func main(){ var x,y int ...
- ORACLE 监听日志文件太大停止写监听日志引起数据库连接不上问题
生产库监听日志文件太大(达到4G多),发现oracle停止写监听日志,检查参数log_file,log_directory,log_status 均正常,数据库运行也正常. 经确认确实为监听日志过大引 ...
- 报错:LINQ to Entities 不识别方法
大致是: var products = db.Products.Select(new ProductVm{Name=SomeMethod() }); 针对IQueryable集合的查询操作会被LINQ ...
- [转] sql_id VS hash_value
有没有发现,v$session,v$sql,v$sqlarea,v$sqltext,v$sql_shared_cursor等试图连接的时候经常会用到hash_value,sql_id,但是他们2个之间 ...
- ubuntu 16.04 vnc server
安装方法 https://help.ubuntu.com/community/VNC/Servers#vino 系统默认自带的,通过搜索Remote Desktop来找到它 配置好之后,设定一下密码 ...
- db2 表授权语句
grant insert/update/delete on table schema.table_name to user user_name;
- MVC使用基架添加控制器出现的错误:无法检索XXX的元数据
环境 vs2012 框架 mvc3 数据库 sqlservercompact4.0 出现的错误如下: “ ---------------------------Microsoft Visual St ...
- 修改maven一更新jre就变成1.5版本
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> ...