回《【开源】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控制器的更多相关文章

  1. 十二、EnterpriseFrameWork框架核心类库之与EntLib结合

    从本章开始对框架的讲叙开始进入核心类库的讲解,前面都是对框架外在功能讲解,让人有个整体的概念,知道包含哪些功能与对系统开发有什么帮助.以后多章都是讲解核心类库的,讲解的方式基本按照代码的目录结构,这样 ...

  2. 十七、EnterpriseFrameWork框架核心类库之Web控制器

    回<[开源]EnterpriseFrameWork框架系列文章索引> EFW框架源代码下载:http://pan.baidu.com/s/1qWJjo3U EFW框架中的WebContro ...

  3. 十五、EnterpriseFrameWork框架核心类库之系统启动入口与初始化

    本章内容是讲三种开发模式,web模式.Winform模式和Wcf模式的系统启动入口有什么区别,以及启动后系统初始化的内容:为什么要把这些单独提出来讲一章,因为我觉得本章非常重要,我们都知道程序中的ma ...

  4. 十四、EnterpriseFrameWork框架核心类库之简易ORM

    在写本章前先去网上找了一下关于ORM的相关资料,以为本章做准备,发现很多东西今天才了解,所以在这里也对ORM做不了太深入的分析,但还是浅谈一下EFW框架中的设计的简易ORM:文中有一点讲得很有道理,D ...

  5. 十六、【适合中小企业的.Net轻量级开源框架】EnterpriseFrameWork框架核心类库之单点登录SSO

    回<[开源]EnterpriseFrameWork框架系列文章索引> EFW框架源代码下载:http://pan.baidu.com/s/1qWJjo3U 单点登录(Single Sign ...

  6. 十九、【.Net开源】EFW框架核心类库之WCF控制器

    回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.1:http://pan.baidu.com/s/1qWJjo3U EFW框架实例源代码下载:http://pan.baid ...

  7. 十三、EnterpriseFrameWork框架核心类库之数据库操作(多数据库事务处理)

    本章介绍框架中封装的数据库操作的一些功能,在实现的过程中费了不少心思,针对不同数据库的操作(SQLServer.Oracle.DB2)这方面还是比较简单的,用工厂模式就能很好解决,反而是在多数据库同时 ...

  8. 二十、【.Net开源】EFW框架核心类库之WebService服务

    回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.1:http://pan.baidu.com/s/1qWJjo3U EFW框架实例源代码下载:http://pan.baid ...

  9. 嵌入式Linux驱动笔记(十八)------浅析V4L2框架之ioctl【转】

    转自:https://blog.csdn.net/Guet_Kite/article/details/78574781 权声明:本文为 风筝 博主原创文章,未经博主允许不得转载!!!!!!谢谢合作 h ...

随机推荐

  1. MySQL数据库主键设计原则

    目录 1. 主键定义... 5 2. 主键设计原则... 5 2.1 确保主键的无意义性... 5 2.2 采用整型主键... 5 2.3 减少主键的变动... 5 2.4 避免重复使用主键... 6 ...

  2. duilib进阶教程 -- 扩展duilib的消息 (11)

    duilib并没有提供双击和右键消息,所以需要我们自行扩展,这里以添加双击消息为例, 在UIDefine.h里,我们只看到了DUI_MSGTYPE_CLICK消息,却没有看到双击消息,因此需要在这里添 ...

  3. pl/sql死锁oracle

    http://jingyan.baidu.com/album/3ea51489eb65b152e61bba8b.html?picindex=2

  4. This in JavaScript

    声明 本文仅为读书笔记并致力于理解Js中的this关键字.如有雷同,纯属巧合.原因有二,其一:有幸看了同一本书,其二:this这玩意已被说烂了~ 为什么要用this? this提供了优雅的方式隐式传递 ...

  5. python一个简单的登录

    文件目录下有两个文件 user_name.txt lock_file.txt 实际中可以读数据库里的信息 代码如下 #encoding = utf-8 import sys user_file = ' ...

  6. Android---真机调试时不能识别手机的解决方案

    我自己遇到的问题是VS2013和VS2015中xamarin无法识别到真机,现象就是插上手机开启调试模式,豌豆荚都可以连接上手机,就是VS上没出现手机. 但是低版本的手机貌似又行,4.0.3的. 于是 ...

  7. SQL Developer 4.0 启动报错“unable to create an instance of the java virtual machine located at path”

    安装了Oracle之后,第一件事情就是想想怎么去连接,进而操作.SQL Developer是官方提供的强大工具,个人看来也是第一选择. 目前官网提供的最新版是4.0.1.14.48,下载下来之后,就跃 ...

  8. 小白学数据分析----->留存率与运营活动分析_I

    有关留存率的事情最近扯得比较多,因为在分析数据的时候,越发觉得,分析一定是要来解决问题的,留存率不知何时突然变得流行了,在此讨论留存率倒不是因为流行,而是觉得以留存率为核心,的确是可以帮助我们解决不少 ...

  9. 【转】我应该直接学Swift还是Objective-C?

    (本文作者Amit Bijlani,由CocoaChina翻译) 当我们发布了Swift语言学习课程之后,收到了很多邮件和私信来问自己是否还需要学习C或者Objective-C.此外,人们似乎还在迷惑 ...

  10. 在github上写博客

    在github上混了几个月,收获颇多.作为一个开源的坚定信仰者,深深觉得每一个码农都应该参与到开源社区中,github提供了一个平台,让你为开源项目提交代码变得异常简单和直接.以前由于工作异常繁忙和繁 ...