WebForm与Mvc

我简单说一下WebForm与Mvc,WebForm是微软很早就推出的一种WEB开发架构,微软对其进行了大量的封装,使开发人员可以像开发桌面程序一样去开发WEB程序,虽然开发效率得到了提高,但可控性会一差。而MVC框架的出现,使WEB开发又回到了请求与响应的开发模式下,可控性增强了,但开发难度也增加了,所以说在架构的选择上没有好与坏,只有适合自己的才是最好的。

FineUIMvc与IFrame

虽然FineUIMvc基于MVC架构,但是也沿用了WebForm页面开发的方式,所以一开始刚接触FineUIMvc时还有一点疑惑。在FineUIMvc中的控制器与视图之间存在着一定的耦合,但这对FineUIMvc来说应该不是什么问题,因为FineUIMvc本身并不是一个通用型的架构,FineUIMvc更适合拥有大量控件操作的项目,耦合的存在可以降低控件的操作难度。在官网的示例中,我们经常能看到在一个控制器中有多个可以返回视图的Action,特别是AppBoxMvc更是达到极致,一个控制器几乎包含了整个项目的全部分代码,这是我所不推荐的做法,所以我在后面对这方面会做一些约束。

在FineUIMvc中有很多容器控件都可以启用IFrame,IFrame之间的交互,在官网示例(http://fineui.com/demo_mvc/)的内联框架中也给出了示例,在这些示例中,大家经常会看到在很多地方都在调用ActiveWindow中的方法,这个也是FineUIMvc对活动窗体的封装。那你在调用ActiveWindow中的方法时,你就已明确的知道,当前的页面是在一个窗体中显示的,并且还是一个活动窗体,如果我们想重用这个页面,并将其放到其它非窗体的容器中,我们要么需要在页面中判断,要么再重新创建一个新的页面,这样必然会对页面的重用带来一些麻烦,同时如果需要在页面间传递一些数据,页面还需要事先知道父页面或同级页面中的方法,这也无形中增加了页面与页面之间的耦合。

FineUIMvc组件开发的基本概念

如果基于组件的方式去开发FineUIMvc项目,这样就可以解决上面所遇到的问题。首先组件是封闭性的,你只需要暴露你想暴露的事件与方法,同时组件不需要知道调用者的信息,调用者只需要监控组件所提供的事件,调用组件所提供的方法,就可以完成组件的操作。我们这里所指的组件,主要是在FineUIMvc中通过IFrame显示的页面,IFrame本身可以起到上下文隔离的作用,再加上在IFrame中显示的页面以组件的方式提供服务,这样页面的开发可以独立出来,而不用去考虑调用者所处在的上下文。

FineUIMvc组件的构成

通过上面的介绍大家应该都知道,我们这里的组件其实就是页面,组件与组件之间的交互,其实就是页面与页面之间的交互。一个页面一般要包含HTML文件、CSS文件及JS文件,由于我们是基于TS开发,所以这里的JS文件就是TS文件,HTML文件对应到MVC中就是CSHTML视图文件。如果我们要创建一个UserInfoComponent组件,那它对应到MVC中应该包含哪些文件及是什么样的结构呢,请看下图

图中用箭头所指向的文件就是我们UserInfoComponent组件所需要的文件,有人可能会问,开发一个组件需要这么文件吗,那组件的开发是不是很复杂。为了使前后端的开发更顺畅,我们需要一些辅助文件,所以这些文件都是必须的,但大家也不用担心,因为这些文件是通过FineUIMvcTools插件自动生成的,并且会在你更改视图及控制器代码时,会自动更新相应的文件。下面是这些文件说明:

  1. UserInfoController.cs:这是MVC中的控制器文件,与普通控制器文件一样没有什么区别
  2. UserInfoController.g.cs:控件引用定义文件,由工具生成,方便直接操作视图中的控件
  3. UserInfoModels.cs:模型文件,这个文件中包含了与当前控制器相关的模型,其中有些模型是自动生成的
  4. Index.cshtml:视图文件,对应控制器中的Index方法
  5. Index.css:视图文件的样式文件
  6. Main.cs:组件引导文件,由工具生成,一般不用修改此文件
  7. UserInfoComponent.ts:组件的TS逻辑文件,组件在客户端的逻辑代码
  8. UserInfoComponent.g.ts:组件的TS辅助文件,由工具生成,包含了控件TS引用定义、模型TS引用定义 及TS的控制器中Action的调用方法

UserInfoComponent组件的开发过程

下面为UserInfoComponent组件的内容,4个文本框及2个按钮,4个文本框的数据来源于外部调用者的设置,“确定”及“取消”按钮触发事件通知调用者

当我们创建完视图时,工具会自动帮助我们生成代码

UserInfoController.g.cs中的代码:

 //
 // 此代码由工具生成
 // 对此文件的修改,将会在下次生成时丢失
 //

 using FineUIMvc;
 using System.Collections.Generic;

 namespace FineUIMvc.EmptyProject.Controllers
 {
     public partial class UserInfoController
     {
         private Dictionary<string, IControlBaseAjaxHelper<ControlBase>> _FINE_UI_MVC_CONTROLS_ = new Dictionary<string, IControlBaseAjaxHelper<ControlBase>>();

         private TextBoxAjaxHelper txtName
         {
             get
             {
                 var controlId = "txtName";

                 if (!this._FINE_UI_MVC_CONTROLS_.ContainsKey(controlId))
                 {
                     this._FINE_UI_MVC_CONTROLS_[controlId] = UIHelper.TextBox(controlId);
                 }

                 return (TextBoxAjaxHelper)this._FINE_UI_MVC_CONTROLS_[controlId];
             }
         }

         private TextBoxAjaxHelper txtEmail
         {
             get
             {
                 var controlId = "txtEmail";

                 if (!this._FINE_UI_MVC_CONTROLS_.ContainsKey(controlId))
                 {
                     this._FINE_UI_MVC_CONTROLS_[controlId] = UIHelper.TextBox(controlId);
                 }

                 return (TextBoxAjaxHelper)this._FINE_UI_MVC_CONTROLS_[controlId];
             }
         }

         private TextBoxAjaxHelper txtTelphone
         {
             get
             {
                 var controlId = "txtTelphone";

                 if (!this._FINE_UI_MVC_CONTROLS_.ContainsKey(controlId))
                 {
                     this._FINE_UI_MVC_CONTROLS_[controlId] = UIHelper.TextBox(controlId);
                 }

                 return (TextBoxAjaxHelper)this._FINE_UI_MVC_CONTROLS_[controlId];
             }
         }

         private TextBoxAjaxHelper txtAddress
         {
             get
             {
                 var controlId = "txtAddress";

                 if (!this._FINE_UI_MVC_CONTROLS_.ContainsKey(controlId))
                 {
                     this._FINE_UI_MVC_CONTROLS_[controlId] = UIHelper.TextBox(controlId);
                 }

                 return (TextBoxAjaxHelper)this._FINE_UI_MVC_CONTROLS_[controlId];
             }
         }

         private ButtonAjaxHelper btnOK
         {
             get
             {
                 var controlId = "btnOK";

                 if (!this._FINE_UI_MVC_CONTROLS_.ContainsKey(controlId))
                 {
                     this._FINE_UI_MVC_CONTROLS_[controlId] = UIHelper.Button(controlId);
                 }

                 return (ButtonAjaxHelper)this._FINE_UI_MVC_CONTROLS_[controlId];
             }
         }

         private ButtonAjaxHelper btnCancel
         {
             get
             {
                 var controlId = "btnCancel";

                 if (!this._FINE_UI_MVC_CONTROLS_.ContainsKey(controlId))
                 {
                     this._FINE_UI_MVC_CONTROLS_[controlId] = UIHelper.Button(controlId);
                 }

                 return (ButtonAjaxHelper)this._FINE_UI_MVC_CONTROLS_[controlId];
             }
         }
     }
 }

UserInfoComponent.g.ts中的代码:

 //
 // 此代码由工具生成
 // 对此文件的修改,将会在下次生成时丢失
 //

 /*
  * UI
  */
 export module UI {
     export let txtName = F<F.TextBox>('txtName');
     export let txtEmail = F<F.TextBox>('txtEmail');
     export let txtTelphone = F<F.TextBox>('txtTelphone');
     export let txtAddress = F<F.TextBox>('txtAddress');
     export let btnOK = F<F.Button>('btnOK');
     export let btnCancel = F<F.Button>('btnCancel');
 }

 /*
  * Action
  */
 export module Action {
     export function getActionUrl(actionName: string) {
         return `${F.baseUrl}UserInfo/${actionName}`;
     }

     export function index(model?: Model.IndexModel, owner?: Window | GetIFrameWindow) {
         let url = `${getActionUrl('Index')}${model != null ? '?' + QueryString.stringify(model) : ''}`;
         let wnd : any = owner || window;
         wnd = (wnd != null && wnd.getIFrameWindow && wnd.getIFrameWindow()) || wnd;
         wnd.open(url, '_self');
     }
 }

 /*
  * Model
  */
 export module Model {

     export class IndexModel {

         constructor() {
         }
     }

 }

外部调用者设置组件的信息,我们需要在UserInfoComponent.ts中去实现(23行到53行为自己添加的代码,其它的为创建时自动生成的代码),代码:

 import { Component } from '../../Scripts/Component';
 import { UI, Action, Model } from './UserInfoComponent.g';

 export class UserInfoComponent extends Component {
     public static readonly TYPE = 'FINEUIMVC_EMPTYPROJECT_VIEWS_USERINFOCOMPONENT';

     constructor() {
         super(UserInfoComponent.TYPE);
         this.init();
     }

     public static validType(component: Component) {
         return component.isType(UserInfoComponent.TYPE);
     }

     public static open(model?: Model.IndexModel, owner?: Window | GetIFrameWindow) {
         Action.index(model, owner);
     }

     private init() {
     }

     public set userName(name: string) {
         UI.txtName.setText(name, false);
     }

     public get userName() {
         return UI.txtName.getText();
     }

     public set email(email: string) {
         UI.txtEmail.setText(email, false);
     }

     public get email() {
         return UI.txtEmail.getText();
     }

     public set telphone(telphone: string) {
         UI.txtTelphone.setText(telphone, false);
     }

     public get telphone() {
         return UI.txtTelphone.getText();
     }

     public set address(address: string) {
         UI.txtAddress.setText(address, false);
     }

     public get address() {
         return UI.txtAddress.getText();
     }
 }

外部调用者监听组件事件,我们还是需要在UserInfoComponent.ts中去实现(20行到36行为自己添加的代码),代码:

 import { Component } from '../../Scripts/Component';
 import { UI, Action, Model } from './UserInfoComponent.g';

 export class UserInfoComponent extends Component {
     public static readonly TYPE = 'FINEUIMVC_EMPTYPROJECT_VIEWS_USERINFOCOMPONENT';

     constructor() {
         super(UserInfoComponent.TYPE);
         this.init();
     }

     public static validType(component: Component) {
         return component.isType(UserInfoComponent.TYPE);
     }

     public static open(model?: Model.IndexModel, owner?: Window | GetIFrameWindow) {
         Action.index(model, owner);
     }

     private init() {
         UI.btnOK.onClick(() => {
             $(document).trigger('onOKClick');
         });

         UI.btnCancel.onClick(() => {
             $(document).trigger('onCancelClick');
         });
     }

     public onOKClick(handler: (e, m) => any) {
         $(document).on('onOKClick', handler);
     }

     public onCancelClick(handler: (e, m) => any) {
         $(document).on('onCancelClick', handler);
     }

     public set userName(name: string) {
         UI.txtName.setText(name, false);
     }

     public get userName() {
         return UI.txtName.getText();
     }

     public set email(email: string) {
         UI.txtEmail.setText(email, false);
     }

     public get email() {
         return UI.txtEmail.getText();
     }

     public set telphone(telphone: string) {
         UI.txtTelphone.setText(telphone, false);
     }

     public get telphone() {
         return UI.txtTelphone.getText();
     }

     public set address(address: string) {
         UI.txtAddress.setText(address, false);
     }

     public get address() {
         return UI.txtAddress.getText();
     }
 }

调用者本身也是一个组件,组件中含有一个Window控件,用于加载UserInfoComponent组件(22行到45行为调用UserInfoComponent,第3行为导入UserInfoComponent),代码:

 import { Component } from '../../Scripts/Component';
 import { UI, Action, Model } from './DefaultComponent.g';
 import { UserInfoComponent } from '../UserInfo/UserInfoComponent';

 export class DefaultComponent extends Component {
     public static readonly TYPE = 'FINEUIMVC_EMPTYPROJECT_VIEWS_DEFAULTCOMPONENT';

     constructor() {
         super(DefaultComponent.TYPE);
         this.init();
     }

     public static validType(component: Component) {
         return component.isType(DefaultComponent.TYPE);
     }

     public static open(model?: Model.IndexModel, owner?: Window | GetIFrameWindow) {
         Action.index(model, owner);
     }

     private init() {
         UserInfoComponent.open(null, UI.window1);
         UI.window1.onReady(() => {
             let userInfoComponent = UI.window1.getComponent<UserInfoComponent>();
             if (userInfoComponent && UserInfoComponent.validType(userInfoComponent)) {
                 userInfoComponent.userName = '张三';
                 userInfoComponent.email = 'test@test.com';
                 userInfoComponent.telphone = ';
                 userInfoComponent.address = 'xxxxxxxxxxx';

                 userInfoComponent.onOKClick(() => {
                     F.notify({
                         message: `姓名:${userInfoComponent.userName};邮箱:${userInfoComponent.email}`,
                         messageIcon: F.MessageBoxIcon.$Success
                     });
                 });

                 userInfoComponent.onCancelClick(() => {
                     F.notify({
                         message: '单击了取消按钮',
                         messageIcon: F.MessageBoxIcon.$Warning
                     });
                 });
             }
         });
     }
 }

运行后的效果(修改完姓名及邮箱后,单击“确定”按钮),如图:

以上就是组件开发的过程,基于组件方式的开发,可以最大程度的提高页面重复利用次数,降低页面与页面之间的耦合。

在后续的文章中,我会介绍组件开发的每一个细节,FineUIMvcTools工具还在完善中,我想等到这个系列文章写完后,再提供给大家。

示例代码:

链接: http://pan.baidu.com/s/1o7AgH2y 密码: 6b33

基于TypeScript的FineUIMvc组件式开发(概述)的更多相关文章

  1. 基于TypeScript的FineUIMvc组件式开发(开头篇)

    了解FineUIMvc的都知道,FineUIMvc中采用了大量的IFrame框架,对于IFrame的优缺点网上也有很多的讨论,这里我要说它的一个优点“有助于隔离代码逻辑”,这也是FineUIMvc官网 ...

  2. Agile.Net 组件式开发平台 - 平台系统介绍

    平台介绍 Agile.Net 组件式开发平台是一款针对企业级产品的开发框架,平台架构基于SOA服务体系,多层组件式架构打造.平台提供企业应用开发所需的诸如ORM.IOC.WCF.EBS.SOA等分布式 ...

  3. PIE SDK组件式开发综合运用示例

    1. 功能概述 关于PIE SDK的功能开发,在我们的博客上已经分门别类的进行了展示,点击PIESat博客就可以访问,为了初学者入门,本章节将对从PIE SDK组件式二次开发如何搭建界面.如何综合开发 ...

  4. Agile.Net 组件式开发平台 - 驱动开发示例

    首先讲一下概念,此驱动非彼驱动.在Agle.Net中我们将组件规划成两种类型,一种是基于业务的窗体组件,一种是提供扩展功能的驱动组件. 打个比方例如一般系统中需要提供身份证读卡功能,然而市面上有很多种 ...

  5. 基于NodeJS的全栈式开发

    前言 为了解决传统Web开发模式带来的各种问题,我们进行了许多尝试,但由于前/后端的物理鸿沟,尝试的方案都大同小异.痛定思痛,今天我们重新思考了“前后端”的定义,引入前端同学都熟悉的 NodeJS,试 ...

  6. (转)也谈基于NodeJS的全栈式开发(基于NodeJS的前后端分离)

    原文链接:http://ued.taobao.org/blog/2014/04/full-stack-development-with-nodejs/ 随着不同终端(pad/mobile/pc)的兴起 ...

  7. Agile.Net 组件式开发平台 - 组件开发示例

    所谓组件式开发平台,它所有的功能模块都是以组件的形式扩展的,下面我来演示一个简单的组件开发例程. Agile.Net开发管理平台项目,已经托管在开源中国码云平台(http://git.oschina. ...

  8. 也谈基于NodeJS的全栈式开发(基于NodeJS的前后端分离)

    前言 为了解决传统Web开发模式带来的各种问题,我们进行了许多尝试,但由于前/后端的物理鸿沟,尝试的方案都大同小异.痛定思痛,今天我们重新思考了“前后端”的定义,引入前端同学都熟悉的NodeJS,试图 ...

  9. 在基于TypeScript的LayaAir HTML5游戏开发中使用AMD

    在基于TypeScript的LayaAir HTML5游戏开发中使用AMD AMD AMD是"Asynchronous Module Definition"的缩写,意思就是&quo ...

随机推荐

  1. QTP自动化测试培训:描述编程之WebElement

    QTP自动化测试培训:描述编程之WebElement   通过描述性编程技术,来描述出来输入框: set po=browser("creationtime:=0").page(&q ...

  2. 使用 SLF4J + LogBack 构建日志系统(转)

    转载自:http://www.cnblogs.com/mailingfeng/p/3499436.html 上次我们讨论了如何选择一个好的开源日志系统方案,其中的结论是:使用 SLF4J + LogB ...

  3. ajax多次请求,只执行最后一次的方法

    ajax多次请求,只执行最后一次的方法 有时候点击按钮进行异步请求数据的时候可能网络差,用户会点击很多次,或者页面有很多相同的按钮,参数不同,但是调用的ajax相同,只想得到最后一次结果 我的思路是用 ...

  4. SSH整合总结(xml与注解)

    本人自己进行的SSH整合,中间遇到不少问题,特此做些总结,仅供参考. 一.使用XML配置: SSH版本 Struts-2.3.31 Spring-4.3.5 Hibernate-4.2.21 引入ja ...

  5. C字符串处理函数

    部分参考百科. C常用字符串函数:字符串输入函数,字符串输出函数,字符串处理函数,标准输入输出流 字符串处理函数: 1.字符串长度:strlen(str),返回字符串实际长度,不包括'\0',返回值类 ...

  6. 详谈 Unity3D AssetBundle 资源加载,结合实际项目开发实例

    第一次搞资源更新方面,这里只说更新,加载,AssetBundle资源加载,谈谈自己的理解,以及自己在项目中遇到的那些神坑,现在回想一下,真的是自己跪着过来的,说多了,都是泪. 我这边是安卓AssetB ...

  7. User Browsing Model简介

    搜索引擎的点击日志提供了很多有价值的query-doc相关性信息,但是这些信息是有偏的,因为对于用户没有点击过的doc,我们无法确定其是否真实地被用户浏览过.即日志中记录的展现信息与实际的展现信息之间 ...

  8. UE4 Fade out Mesh

    由于项目需要一个将场景慢慢淡入以及淡出的效果,所以就想了想实现思路.因为PBR光照模型是不支持透明物体的渲染的,所以UE4中的PBR材质在为Opaque时是无法改变透明度的,想来想去想不出解决方法,然 ...

  9. jquery分页插件的修改

    前言 最近分页功能使用的比较多,所以从网上下载个jquery分页插件来使用, 之前用的都挺好的,直到昨天出现了逻辑问题,反复查看自己的代码,最后发现是点击页码后执行了多个点击事件.最后只有自己查看源码 ...

  10. 【正常向】CODEVS上分黄金

    白银上分黄金失败=.= 在之前有很认真的写了一波排序,所以排序并不是很怂,还是那个理,现阶段学习的都是比较简单的排序,都是所谓的冒泡排序啊,桶排序这类,至于插排和选择排序,再往后又是什么快拍就很尬了. ...