您好,登錄后才能下訂單哦!
本篇文章為大家展示了asp.net mvc4中怎樣快速開發代碼生成器,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
一、前言
作為一個碼農這么多年,一直在想怎么提高我們的編碼效率,關于如何提高編碼效率,我自己的幾點體會
1、清晰的項目結構,要編寫代碼的地方集中
2、實現相同功能的代碼量少并且清晰易懂
3、重復或有規律的代碼應該自動生成
在這里我就討論下代碼生成的問題。
二、關于代碼生成器
剛畢業時我也非常迷信代碼生成器,喜歡在網上找一些代碼生成器及相關的源碼,喜歡在和網友討論哪款生成器好用,但實際上很少真正用這些東西來開發項目,原因很簡單:
1、生成出來的代碼不是我們要的代碼
2、生成后的代碼再修修改改,其實還沒有我的ctrl+c和ctrl+v速度快。
3、生成的基本上是實體類及sql拼接代碼,現在直接用linq或一些好用的orm多方便,誰還用SQLHelper加sql文拼接?
4、b/s項目中沒有一個生成器能很好的能生成UI層代碼及前端交互的js代碼,即使能生成也是簡單的頁面。
所以,我勸大家不要迷信代碼生成器了。它的確可以提高我們的效率,但是并不是網上你找一個生成器就行的。代碼生成器它只是一個模板引擎而已,最重要的不是代碼生成器本身,而是對一類功能或一類頁面的代碼規范,對自己代碼的提煉,提煉出一個通用的模板。
比如我們常見的查詢頁面,錄入頁面等,我們只要提煉一個標準的查詢頁面的代碼,包括前臺html,前臺js,后臺控制器,后臺數據服務。然后把它寫成模板,再利用模板引擎就可以生成我們需要的代碼了。
代碼生成器本身就是模板引擎,所以我覺得***的代碼生成器不是網上流傳的那些可以生成三層架構代碼的軟件,而是微軟的razor引擎,非常簡潔易懂,而且做過asp.net mvc項目的朋友應該也很熟悉。我個人覺得這是用來做代碼生成***的引擎。
三、頁面模板
我們還是會想要快速開發,比如我選擇了一些設定之后,就可以直接生成我想要的代碼包括html及js,拷貝到項目中就可以直接運行,運行后就看到我想要的頁面,基本功能都有。當然這里所說的快速開發是建立在我對頁面功能的提煉模板之上的。實際上我提煉了三種模板:
1、查詢頁面
這個模板可以解決大部分的查詢報表業務功能
2、編輯頁面
這個編輯模板可以解決基本上所有的錄入功能,因為包括了主表,及多個從表(1:N或1:1)錄入,而且可以一次性在同一事務中保存。并且定義了很多觸發前后事件用于寫一些業務處理,并且做到差異更新。
3、查詢編輯頁面,可以查詢也可以直接在grid中編輯,這個頁面用于做一些簡單單據或一些基礎數據頁面。
四、代碼生成原理
把以上頁面代碼做成razor模板,razor模板 + 設定選項 ==razor引擎==> 頁面代碼
怎么利用razor引擎,其實有以下幾種方法:
1、直接利用mvc的view輸出功能,以下為關鍵代碼
var stringWriter = new StringWriter(); var viewContext = new ViewContext(controllerContext, view, viewData, TempData, stringWriter); view.Render(viewContext, stringWriter); var result = stringWriter.ToString();
用這種方法的優點在于不需要引入第三方類庫,直接調用mvc視圖的Render方法生成,而且效率很高,缺點是controllerContext及view對象的構建獲取非常復雜。這種方法適用于有潔辟的碼農們,我屬于這一種。
2、利用第三方類庫RazorEngine輸出,以下為關鍵代碼
var template = "Hello @Model.Name! Welcome to Razor!"; var viewData = new { Name = "World" }); var result = Razor.Parse(template, viewData);
這代碼很清爽,一目了然,只不過要引入RazorEngine類庫,而且效率不如前者。
五、代碼生成用戶界面
我們模板準備好了,引擎準備好了,那么還需要一個數據輸入viewData,我們做用戶界面的目的也就是為了更好的定義這個viewData。
這個用戶界面我們還是要把三種頁面的定義分開:
1、查詢頁面生成
第一步,選擇代碼類別search(查詢頁面),選擇數據庫,選擇業務主表,再勾選字段即可實現查詢條件部的設置,并且實現了拖拉排序功能。大家可以對照查詢模板看。
第二步,選擇grid中要顯示的列,并且設置屬性,格式化等
第三步,設置一些全局設定,主要根據這些參數確定命名空間,生成文件名等信息
點擊生成按鈕,按設定生成代碼,生成后彈出文件夾,已分別生成MVC三層代碼
mms_receive.cs
Index.cshtml
ReceiveController.cs
把這個代碼直接拷貝到項目中直接運行,測試條件過濾都沒有問題,grid會自適應高度,grid遠程排序,選擇分頁翻頁都沒有問題,所有的功能都可用,
只有lookup控件彈出是空值,因為只把控制設置為了lookup但沒有為它設置更詳細的選項。autocomplete也是同樣
即代碼生成器已經生成了一個大的結構及UI,一些小細節還是要手動修改下,代碼生成的UI界面如果把每個控件的選項也做進去會相當的復雜,也沒有必要再細化了。
2、編輯頁面生成
第一步,選擇主表編輯區的字段及控件類型,控件類型中的高級還未實現,這個編輯的UI也可以參照編輯的模板看
第二步,添加tab頁簽,選擇頁簽類型(grid,form,empty) grid是指跟主表N:1關系,form是指跟主表1:1關系,empty是空頁簽,生成后自己可以添加內容
這里我隨便添加三個tab頁簽tab1 tab2 tab3
tab1用來放人員變動grid(跟主表關系N:1)
tab2就選擇form(跟主表關系1:1,也可以是主表本身)
tab3也隨便添些東西
第三步,其它設置
點擊生成按鈕,生成后自動打開文件夾
把這些代碼拷貝到項目中直接運行
tab2
tab3,修改主表數據,tab1,tab2,tab3點保存,能保存成功,
審核按鈕也可用,審核后單據不可修改
這個編輯功能基本上可以囊括很多的錄入頁面了,可以算是比較通用了
3、查詢編輯頁面(查詢編輯在同一個頁面內)頁面生成
***步,選擇查詢條件并設置控件類型
第二步,設置grid中的數據列,及編輯器
第三步,其它設置
點擊生成按鈕,生成后自動打開文件夾
把代碼直接拷貝到項目中運行,結果如下,經測試除了控件還需要進一步設置,所有按鈕功能正常使用
六、代碼生成頁面的源碼
Index.cshtml
@{ ViewBag.Title = "代碼生成"; Layout = "~/Views/Shared/_Layout.cshtml"; } @section head{ <link href="~/Content/js/jquery-plugins/smartwizard/smart_wizard.css" rel="stylesheet" /> <style type="text/css"> div#navigation{float: left;width: 180px;} div#wrapper{float: right;width: 100%;margin-left: -185px;} div#wizard{margin-left: 185px;} ul.anchor{margin:0 0 10px 0 !important;} ul li{margin-left:-16px;} .grid .z-txt{margin:0 -3px;width:90%;} .grid input{width:90%;} .grid input[type=checkbox]{cursor:default;} .grid select{width:80%;padding:0 !important;height:22px;} .grid select + a{margin:5px;} .tDnD_whileDrag{background-color: #FBEC88 !important;} </style> } @section scripts{ <script src="~/Content/js/jquery-plugins/smartwizard/jquery.smartWizard.js"></script> <script src="~/Content/js/jquery-extend/jquery.tablednd.js"></script> @Scripts.Render("~/Resource/Sys/Generator.js") <script type="text/javascript"> $(function () { ko.applyBindings(new viewModel()); }); </script> } <div id="container"> <div id="navigation"> <div class="panel-header" style="width: 168px; border-width: 0; background: #FAFAFA;"> 代碼類別 <input type="text" class="z-txt" data-bind="easyuiCombobox:codetype" /> <div style="margin:1px;"></div> 數據庫名 <input type="text" class="z-txt" data-bind="easyuiCombobox:database" /> <div style="margin:5px;"></div> <div data-bind="autoheight:60" style="width: 172px; border-width: 0;margin:0;padding:0; background: #FAFAFA; overflow:auto;"> <ul data-bind="easyuiTree:tabletree"></ul> </div> </div> </div> <div id="wrapper"> <div id="wizard" class="swMain" style="width:100%"></div> </div> </div> <script id="template-searchEdit" type="text/html"> <ul> <li><a href="#step-1"> <label class="stepNumber">1</label> <span class="stepDesc">設置條件部<br /> <small>定義查詢條件</small> </span> </a></li> <li><a href="#step-2"> <label class="stepNumber">2</label> <span class="stepDesc">設置數據列<br /> <small>定義查詢顯示的數據字段</small> </span> </a></li> <li><a href="#step-3"> <label class="stepNumber">3</label> <span class="stepDesc">其它設置<br /> <small>修改其它代碼生成設置</small> </span> </a></li> </ul> <div id="step-1" class="step"> <h3 class="StepTitle">***步 請勾選要查詢的字段</h3> <div> <div style="width:200px;float:left;overflow:auto;" data-bind="autoheight:172"> <ul data-bind="easyuiTree:searchEdit.columntree"></ul> </div> <div style="float:left;overflow:auto" data-bind="autoheight:172,autowidth:405"> <table class="grid"> <thead> <tr> <th style="width:50px">字段</th> <th style="width:120px">顯示名稱</th> <th style="width:120px">控件類型</th> @*<th >參數</th>*@ <th style="width:80px">查詢邏輯</th> </tr> </thead> <tbody data-bind="foreach:form.conditions"> <tr data-bind="attr:{id:$index}"> <td data-bind="text:field" style="text-align:left"></td> <td><input type="text" class="z-txt" data-bind="value:title"/></td> <td><select class="z-txt" data-bind="options:$root.data.input,value:type"></select></td> @*<td><input type="text" class="z-txt" data-bind="value:options"/></td>*@ <td><select class="z-txt" data-bind="options:$root.data.compare,value:cp"></select></td> </tr> </tbody> </table> </div> </div> </div> <div id="step-2" class="step"> <h3 class="StepTitle">第二步 請勾選要顯示的數據字段</h3> <div style="width:200px;float:left;overflow:auto;" data-bind="autoheight:172"> <ul data-bind="easyuiTree:searchEdit.columntree2"></ul> </div> <div style="float:left;overflow:auto" data-bind="autoheight:172,autowidth:405"> <table class="grid"> <thead> <tr> <th style="width:50px">字段</th> <th style="width:100px">題頭</th> <th style="width:30px">隱藏</th> <th style="width:30px">排序</th> <th style="width:50px">對齊</th> <th style="width:40px">寬度</th> <th style="width:50px">格式化</th> <th style="width:50px">編輯器</th> </tr> </thead> <tbody data-bind="foreach:form.columns"> <tr data-bind="attr:{id:$index}"> <td data-bind="text:field" style="text-align:left"></td> <td><input type="text" class="z-txt" data-bind="value:title" /></td> <td><input type="checkbox" data-bind="checked:hidden"/></td> <td><input type="checkbox" data-bind="checked:sortable"/></td> <td><select class="z-txt" data-bind="options:$root.data.align,value:align" ></select></td> <td><input type="text" class="z-txt" data-bind="value:width" /></td> <td><select class="z-txt" data-bind="options:$root.data.formatter,optionsText:'text',optionsValue:'value',value:formatter" ></select></td> <td><select class="z-txt" data-bind="options:$root.data.editor,optionsText:'text',optionsValue:'value',value:editor" ></select></td> </tr> </tbody> </table> </div> </div> <div id="step-3" class="step"> <h3 class="StepTitle">第三步 其它設置</h3> <div class="container_12"> <div class="grid_1 lbl">業務區域</div> <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.area"/></div> <div class="clear"></div> <div class="grid_1 lbl">控制器名稱</div> <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.controller"/></div> <div class="clear"></div> <div class="grid_1 lbl">生成路徑</div> <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.path"/></div> </div> </div> </script> <script id="template-search" type="text/html"> <ul> <li><a href="#step-1"> <label class="stepNumber">1</label> <span class="stepDesc">設置條件部<br /> <small>定義查詢條件</small> </span> </a></li> <li><a href="#step-2"> <label class="stepNumber">2</label> <span class="stepDesc">設置數據列<br /> <small>定義查詢顯示的數據字段</small> </span> </a></li> <li><a href="#step-3"> <label class="stepNumber">3</label> <span class="stepDesc">其它設置<br /> <small>修改其它代碼生成設置</small> </span> </a></li> </ul> <div id="step-1" class="step"> <h3 class="StepTitle">***步 請勾選要查詢的字段</h3> <div> <div style="width:200px;float:left;overflow:auto;" data-bind="autoheight:172"> <ul data-bind="easyuiTree:searchEdit.columntree"></ul> </div> <div style="float:left;overflow:auto" data-bind="autoheight:172,autowidth:405"> <table class="grid"> <thead> <tr> <th style="width:50px">字段</th> <th style="width:120px">顯示名稱</th> <th style="width:120px">控件類型</th> @*<th >參數</th>*@ <th style="width:80px">查詢邏輯</th> </tr> </thead> <tbody data-bind="foreach:form.conditions"> <tr data-bind="attr:{id:$index}"> <td data-bind="text:field" style="text-align:left"></td> <td><input type="text" class="z-txt" data-bind="value:title"/></td> <td><select class="z-txt" data-bind="options:$root.data.input,value:type"></select></td> @*<td><input type="text" class="z-txt" data-bind="value:options"/></td>*@ <td><select class="z-txt" data-bind="options:$root.data.compare,value:cp"></select></td> </tr> </tbody> </table> </div> </div> </div> <div id="step-2" class="step"> <h3 class="StepTitle">第二步 請勾選要顯示的數據字段</h3> <div style="width:200px;float:left;overflow:auto;" data-bind="autoheight:172"> <ul data-bind="easyuiTree:searchEdit.columntree2"></ul> </div> <div style="float:left;overflow:auto" data-bind="autoheight:172,autowidth:405"> <table class="grid"> <thead> <tr> <th style="width:50px">字段</th> <th style="width:100px">題頭</th> <th style="width:30px">隱藏</th> <th style="width:30px">排序</th> <th style="width:50px">對齊</th> <th style="width:40px">寬度</th> <th style="width:50px">格式化</th> </tr> </thead> <tbody data-bind="foreach:form.columns"> <tr data-bind="attr:{id:$index}"> <td data-bind="text:field" style="text-align:left"></td> <td><input type="text" class="z-txt" data-bind="value:title" /></td> <td><input type="checkbox" data-bind="checked:hidden"/></td> <td><input type="checkbox" data-bind="checked:sortable"/></td> <td><select class="z-txt" data-bind="options:$root.data.align,value:align" ></select></td> <td><input type="text" class="z-txt" data-bind="value:width" /></td> <td><select class="z-txt" data-bind="options:$root.data.formatter,optionsText:'text',optionsValue:'value',value:formatter" ></select></td> </tr> </tbody> </table> </div> </div> <div id="step-3" class="step"> <h3 class="StepTitle">第三步 其它設置</h3> <div class="container_12"> <div class="grid_1 lbl">業務區域</div> <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.area"/></div> <div class="clear"></div> <div class="grid_1 lbl">控制器名稱</div> <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.controller"/></div> <div class="clear"></div> <div class="grid_1 lbl">生成路徑</div> <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.path"/></div> </div> </div> </script> <script id="template-edit" type="text/html"> <ul> <li><a href="#step-1"> <label class="stepNumber">1</label> <span class="stepDesc">設置主表編輯區<br /> <small>定義主表編輯字段</small> </span> </a></li> <li><a href="#step-2"> <label class="stepNumber">2</label> <span class="stepDesc">設置明細數據頁簽<br /> <small>定義明細表及頁簽</small> </span> </a></li> <li><a href="#step-3"> <label class="stepNumber">3</label> <span class="stepDesc">其它設置<br /> <small>修改其它代碼生成設置</small> </span> </a></li> </ul> <div id="step-1" class="step"> <h3 class="StepTitle">***步 請勾選要編輯的字段</h3> <div> <div style="width:200px;float:left;overflow:auto;" data-bind="autoheight:172"> <ul data-bind="easyuiTree:searchEdit.columntree"></ul> </div> <div style="float:left;overflow:auto" data-bind="autoheight:172,autowidth:405"> <table class="grid"> <thead> <tr> <th style="width:20%">字段</th> <th style="width:40%">標簽名稱</th> <th style="width:30%">控件類型</th> <th style="width:10%">只讀</th> </tr> </thead> <tbody data-bind="foreach:form.conditions"> <tr data-bind="attr:{id:$index}"> <td data-bind="text:field" style="text-align:left"></td> <td><input type="text" class="z-txt" data-bind="value:title"/></td> <td><select class="z-txt" data-bind="options:$root.data.input,value:type" style="width:60%"></select><a href="#">高級</a></td> <td><input type="checkbox" data-bind="checked:readonly"/></td> </tr> </tbody> </table> </div> </div> </div> <div id="step-2" class="step"> <h3 class="StepTitle">第二步 請設置頁面中的tab頁簽</h3> <div style="float:left;overflow:auto;width:150px;" data-bind="autoheight:172"> <a href="#" class="buttonNext" style="float:left;margin:5px 3px 5px 0" data-bind="click:edit.addTab">添加Tab頁簽</a> <table class="grid"> <thead> <tr> <th style="width:30%">#</th> <th style="width:70%">名稱</th> </tr> </thead> <tbody data-bind="foreach:form.tabs"> <tr data-bind="attr:{id:$index}"> <td><a href="#" data-bind="click:$parent.edit.removeTab">刪除</a></td> <td><input type="text" class="z-txt" data-bind="value:title,click:$parent.edit.clickTab" style="width:90%"/></td> </tr> </tbody> </table> </div> <div id="edit-tab-setting" style="float:left;overflow:auto;" data-bind="autoheight:172,autowidth:355,visible:edit.selectedTitle()!=null"> </div> </div> <div id="step-3" class="step"> <h3 class="StepTitle">第三步 其它設置</h3> <div class="container_12"> <div class="grid_1 lbl">業務區域</div> <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.area"/></div> <div class="clear"></div> <div class="grid_1 lbl">控制器名稱</div> <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.controller"/></div> <div class="clear"></div> <div class="grid_1 lbl">生成路徑</div> <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.path"/></div> </div> </div> </script> <script type="text/html" id="template-edit-tab-setting"> <div style="padding:8px;clear:both"> <span>頁簽類型 </span> <select class="z-txt" style="padding:0;height:22px;" data-bind="value:edit.selectedTab.type"> <option value="empty">empty</option> <option value="grid">grid</option> <option value="form">form</option> </select> <span data-bind="visible:edit.selectedTab.type()!='empty'"> 數據表 </span> <select class="z-txt" style="padding:0;height:22px;" data-bind="options:data.table,optionsText:'text',optionsValue:'id',value:edit.selectedTab.subtable,visible:edit.selectedTab.type()!='empty'"></select> <span data-bind="visible:edit.selectedTab.type()!='empty'">與主表的關聯</span> <select class="z-txt" style="padding:0;height:22px;" data-bind="options:data.tablekey,value:edit.selectedTab.relationship,visible:edit.selectedTab.type()!='empty'"></select> </div> <div style="width:180px;float:left;overflow:auto;margin-right:-18px;" data-bind="autoheight:212,visible:edit.selectedTab.type()!='empty'"> <ul data-bind="easyuiTree:edit.columntree2"></ul> </div> <div style="float:right;overflow:auto;" data-bind="autoheight:210,autowidth:535,visible:edit.selectedTab.type()!='empty'"> <table class="grid"> <thead> <tr> <th style="width:50px">字段</th> <th style="width:100px">題頭</th> <th style="width:30px" data-bind="visible:edit.selectedTab.type()=='grid'">隱藏</th> <th style="width:30px" data-bind="visible:edit.selectedTab.type()=='grid'">排序</th> <th style="width:50px" data-bind="visible:edit.selectedTab.type()=='grid'">對齊</th> <th style="width:40px" data-bind="visible:edit.selectedTab.type()=='grid'">寬度</th> <th style="width:50px" data-bind="visible:edit.selectedTab.type()=='grid'">格式化</th> <th style="width:50px" data-bind="visible:edit.selectedTab.type()=='grid'">編輯器</th> <th style="width:50px" data-bind="visible:edit.selectedTab.type()=='form'">控件類型</th> <th style="width:10px" data-bind="visible:edit.selectedTab.type()=='form'">只讀</th> </tr> </thead> <tbody data-bind="foreach:edit.selectedTab.columns"> <tr data-bind="attr:{id:$index}"> <td data-bind="text:field" style="text-align:left"></td> <td><input type="text" class="z-txt" data-bind="value:title" /></td> <td data-bind="visible:$parent.edit.selectedTab.type()=='grid'"><input type="checkbox" data-bind="checked:hidden"/></td> <td data-bind="visible:$parent.edit.selectedTab.type()=='grid'"><input type="checkbox" data-bind="checked:sortable"/></td> <td data-bind="visible:$parent.edit.selectedTab.type()=='grid'"><select class="z-txt" data-bind="options:$root.data.align,value:align" ></select></td> <td data-bind="visible:$parent.edit.selectedTab.type()=='grid'"><input type="text" class="z-txt" data-bind="value:width" /></td> <td data-bind="visible:$parent.edit.selectedTab.type()=='grid'"><select class="z-txt" data-bind="options:$root.data.formatter,optionsText:'text',optionsValue:'value',value:formatter" ></select></td> <td data-bind="visible:$parent.edit.selectedTab.type()=='grid'"><select class="z-txt" data-bind="options:$root.data.editor,optionsText:'text',optionsValue:'value',value:editor" ></select></td> <td data-bind="visible:$parent.edit.selectedTab.type()=='form'"><select class="z-txt" data-bind="options:$root.data.input,value:type"></select></td> <td data-bind="visible:$parent.edit.selectedTab.type()=='form'"><input type="checkbox" data-bind="checked:readonly"/></td> </tr> </tbody> </table> </div> </script>
Generator.js
/** * 模塊名:mms viewModel * 程序名: Generator.js * Copyright(c) 2013 liuhuisheng [ liuhuisheng.xm@gmail.com ] **/ var viewModel = function () { var self = this; this.form = { type: '', database:ko.observable(), table: ko.observable(), controller: ko.observable(), area:ko.observable(), conditions: ko.observableArray(), columns: ko.observableArray(), tabs: ko.observableArray(), path: ko.observable("~/Generator/") }; this.resetForm = function () { self.form.conditions([]); self.form.columns([]); self.form.tabs([]); }; this.data = { codetype: [{ text: 'search', value: 'search' }, { text: 'edit', value: 'edit' }, { text: 'searchEdit', value: 'searchEdit' }], database: ko.observableArray(), table: ko.observableArray(), column:ko.observableArray(), tablekey: ko.observableArray(), input: ['text', 'autocomplete', 'combobox', 'lookup','datebox','daterange'], compare: ['equal', 'like', 'startwith', 'endwith', 'greater', 'less', 'daterange'], align:['left','center','right'], formatter: [{text:'',value:''},{ text: '日期', value: 'com.formatDate' }, { text: '時間', value: 'com.formatTime' }, { text: '金額', value: 'com.formatMoney' }, { text: '是否', value: 'com.formatCheckbox' }], editor: [{text:'',value:''},{ text: '文本', value: 'text'}, { text: '整數', value: "{type: 'numberbox',options:{min: 0}}" }, { text: '兩位小數', value: "{type: 'numberbox',options:{min: 0, precision: 2}}" }, { text: '下拉框', value: "{type:'combobox',options:{}}" }, { text: '彈出框', value: "{type:'lookup',options:{}}" }, { text: '日期', value: 'datebox' }] }; this.initDatabase = function () { com.ajax({ type: 'GET', async:false, url: '/api/sys/generator/GetConnectionStrings', success: function (d) { self.data.database(d); } }); }; this.initDatabase(); this.getTableUrl = function () { return '/api/sys/generator/GetTables?database=' + self.form.database(); }; this.getColumnUrl = function (table) { return '/api/sys/generator/GetColumns?database=' + self.form.database() + "&table=" + table; } this.codetype = { showblank: true, width: 110, data: self.data.codetype, onSelect: function (node) { self.form.type = node.value; self.initWizard(); } }; this.database = { showblank: true, width: 110, data: self.data.database, onSelect: function (node) { self.form.database(node.value) self.form.area((node.value.split('.')[1] || node.value).replace(/(^|\s+)\w/g, function (s) { return s.toUpperCase(); })); } }; this.tabletree = { method: 'GET', url: ko.computed(self.getTableUrl), loadFilter: function (d) { var data = utils.filterProperties(d.rows || d, ['TableName as id', 'TableName as text']); self.data.table(data); return data; }, onSelect: function (node) { self.form.table(node.id); self.edit.init(); self.resetWizard(); self.form.controller((node.id.split('_')[1] || node.id).replace(/(^|\s+)\w/g, function (s) { return s.toUpperCase(); })); } }; this.generator = function () { com.ajax({ type:'POST', url: '/api/sys/generator', data: ko.toJSON(self.form), success: function (d) { com.message('success', "代碼已生成!"); } }); }; this.searchEdit = {}; this.searchEdit.columntree = { method: 'GET', url: ko.computed(function () { return self.getColumnUrl(self.form.table()); }), checkbox: true, loadFilter: function (d) { return utils.filterProperties(d.rows || d, ['ColumnName as id', 'ColumnName as text']); }, onSelect: function (node) { var handle = node.checked ? 'uncheck' : 'check'; $(this).tree(handle, node.target); }, onCheck: function (node, checked) { if (checked) self.form.conditions.push({ field: node.id, title: node.id, type: 'text', options: '', cp: 'equal',readonly:false }); else self.form.conditions.remove(function (item) { return item.field == node.id }); }, onLoadSuccess: self.resetForm }; this.searchEdit.columntree2 = { method: 'GET', url: ko.computed(function () { return self.getColumnUrl(self.form.table()); }), checkbox: true, loadFilter: function (d) { return utils.filterProperties(d.rows || d, ['ColumnName as id', 'ColumnName as text']); }, onSelect: function (node) { var handle = node.checked ? 'uncheck' : 'check'; $(this).tree(handle, node.target); }, onCheck: function (node, checked) { var arr = self.form.columns; if (checked) { var item = $.grep(arr(), function (row) {return row.field == node.id;})[0]; item || arr.push({ field: node.id, title: node.id, hidden: false, sortable: true, align: 'left', width: 80, formatter: '', editor: 'text' }); } else arr.remove(function (item) { return item.field == node.id }); } }; this.edit = {}; this.edit.selectedTab = { title: ko.observable(), type: ko.observable(), subtable: ko.observable(), relationship: ko.observable(), columns: ko.observableArray(), primaryKeys:ko.observableArray() }; this.edit.columntree2 = { method: 'GET', url:ko.observable(), checkbox: true, loadFilter: function (d) { self.data.column(d); var list = utils.filterProperties(d.rows || d, ['ColumnName as id', 'ColumnName as text']); self.edit.setDefaultForm(); self.edit.resetTableKey(); var checkedList = []; for (var i in self.edit.selectedTab.columns()) checkedList.push(self.edit.selectedTab.columns()[i].field); for (var i in list) if ($.inArray(list[i].id, checkedList) > -1) list[i].checked = true; return list }, onSelect: function (node) { var handle = node.checked ? 'uncheck' : 'check'; $(this).tree(handle, node.target); }, onCheck: function (node, checked) { var arr = self.edit.selectedTab.columns; if (checked) { var item = $.grep(arr(), function (row) { return row.field == node.id; })[0]; item || arr.push({ field: node.id, title: node.id, hidden: false, sortable: true, align: 'left', width: 80, formatter: '', editor: 'text', type: '', readonly: true }); } else arr.remove(function (item) { return item.field == node.id }); } } this.edit.init = function () { self.edit.selectedTitle(null); self.edit.selectedTab = null; $('#edit-tab-setting').empty(); }; this.edit.addTab = function () { var title = 'tab' + (self.form.tabs().length + 1); var newTab = { title: ko.observable(title), type: ko.observable('empty'), subtable: ko.observable(self.form.table()), relationship: ko.observable(), columns: ko.observableArray(), primaryKeys:ko.observableArray() }; newTab.type.subscribe(function (value) { if (value == 'grid') { var item = $.grep(self.data.table(), function (row) { return row.id == self.form.table() + "Detail" })[0]; if (item) newTab.subtable(item.id); } else if (value == 'form') { newTab.subtable(self.form.table()); } }); newTab.columns.subscribe(self.tableDnDUpdate); newTab.subtable.subscribe(function (value) { self.edit.selectedTab.columns([]); self.edit.columntree2.url(self.getColumnUrl(value)); }); self.form.tabs.push(newTab); }; this.edit.removeTab = function (row,event) { self.form.tabs.remove(row); if (row.title() == self.edit.selectedTitle()) self.edit.selectedTitle(null); }; this.edit.selectedTitle = ko.observable(); this.edit.clickTab = function (row, event) { if (row.title() == self.edit.selectedTitle()) return; self.edit.selectedTitle(row.title()); self.edit.selectedTab = row; self.edit.columntree2.url = ko.observable(self.getColumnUrl(self.edit.selectedTab.subtable())); var currentTr = $(event.srcElement).parent("td").parent("tr"); currentTr.parent().find("tr.tree-node-selected").removeClass("tree-node-selected"); currentTr.addClass("tree-node-selected"); var tabTemplate = $('#template-edit-tab-setting').html(); var wrapper = $('#edit-tab-setting').empty().html(tabTemplate); ko.cleanNode(wrapper[0]); ko.applyBindings(self, wrapper[0]); wrapper.find("table").tableDnD({ onDrop: self.tableDnDSort }); }; this.edit.resetTableKey = function () { var relationship = self.edit.selectedTab.relationship(); self.data.tablekey([]); var cols = self.data.column(); for (var i in cols) if (cols[i].IsIdentity || cols[i].IsPrimaryKey) self.data.tablekey.push(cols[i].ColumnName); self.edit.selectedTab.relationship(relationship); self.edit.selectedTab.primaryKeys(self.data.tablekey()); }; this.edit.setDefaultForm = function () { var arr = [ { field: 'ApproveState', title: '審批狀態', type: 'text', readonly: true }, { field: 'ApproveRemark', title: '審批意見', type: 'text', readonly: true }, { field: 'ApprovePerson', title: '審批人', type: 'text', readonly: true }, { field: 'ApproveDate', title: '審批日期', type: 'datebox', readonly: true }, { field: 'CreatePerson', title: '編制人', type: 'text', readonly: true }, { field: 'CreateDate', title: '編制日期', type: 'datebox', readonly: true }, { field: 'UpdatePerson', title: '修改人', type: 'text', readonly: true }, { field: 'UpdateDate', title: '修改日期', type: 'datebox', readonly: true } ]; var cols = self.data.column(); var defaults = { field: '', title: '', hidden: false, sortable: true, align: 'left', width: 80, formatter: '', editor: 'text', type: '', readonly: true }; for (var i in arr) { if (!$.grep(cols, function (item) { return item.ColumnName == arr[i].field; }).length) return; arr[i] = $.extend({}, defaults, arr[i]); } self.edit.selectedTab.columns(arr); var tree = self.edit.columntree2.$element(); for (var i in arr) { var node = tree.tree('find', arr[i].field); if (node) tree.tree('check', node.target); } }; this.initWizard = function () { var stepTemplate = $('#template-' + self.form.type); if (!stepTemplate.length) return; var wizard = $('#wizard').removeData('smartWizard').empty(); ko.cleanNode(wizard[0]); wizard.html(stepTemplate.html()); wizard.smartWizard({ labelNext: '下一步', labelPrevious: '上一步', labelFinish: '生成', onFinish: self.generator }); var resizeStep = function () { $(".step").height($(window).height() - 145) .width($(window).width() - 205); $(".actionBar").width($(window).width() - 195); var index = wizard.smartWizard('currentStep'); wizard.smartWizard('goToStep', index); }; $(window).resize(resizeStep); resizeStep(); ko.applyBindings(self, wizard[0]); wizard.find("table").tableDnD({ onDrop: self.tableDnDSort }); for (var i in self.form) { if ($.isFunction(self.form[i])) if (self.form[i]() instanceof Array) if (self.form[i].subscribe) self.form[i].subscribe(self.tableDnDUpdate); } }; this.resetWizard = function () { var wizard = $("#wizard").smartWizard('goToStep', 1); for (var i = 1; i <= wizard.find(">ul>li").length; i++) wizard.smartWizard("disableStep", i); }; this.tableDnDUpdate = function () { setTimeout('$("table").tableDnDUpdate()', 300); }; this.tableDnDSort = function (table, row) { var name = $(table).find("tbody").attr("data-bind").replace('foreach:form.',''); var array = self.form[name], i = 0; if (name == 'foreach:edit.selectedTab.columns') array = self.edit.selectedTab.columns; $("tr[id]", table).each(function () { array()[this.id].id = i++; }); array.sort(function (left, right) { return left.id == right.id ? 0 : (left.id < right.id ? -1 : 1) }); //for fix ko bug refresh ui var tempArr = array(); array([]); array(tempArr); }; };
razor模板
model.cshtml
@using Zephyr.Core.Generator using System; using System.Collections.Generic; using System.Text; using Zephyr.Core; namespace Zephyr.Web.@(@Model.Area).Models { [Module("@Model.Database")] public class @(Model.TableName)Service : ServiceBase<@Model.TableName> { } public class @Model.TableName : ModelBase { @foreach(TableSchema item in Model.Columns) { if (item.IsIdentity) { @:[Identity] } if (item.IsPrimaryKey) { @:[PrimaryKey] } @:public @item.TypeName @item.ColumnName { get; set; } } } }
其它各頁面的模板我就不一一貼出來了,大家可以查看我以前的那些關于共通viewModel的博客,查詢及編輯頁面我都有詳細介紹過,大家也可以自己提煉出自己的一套模板,然后也可以用這同一個思路去做一個代碼生成器。
上述內容就是asp.net mvc4中怎樣快速開發代碼生成器,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。