【番外篇】ASP.NET MVC快速入門之免費jQuery控件庫(MVC5+EF6)

目錄

【第一篇】ASP.NET MVC快速入門之數據庫操做(MVC5+EF6)javascript

【第二篇】ASP.NET MVC快速入門之數據註解(MVC5+EF6)php

【第三篇】ASP.NET MVC快速入門之安全策略(MVC5+EF6)css

【第四篇】ASP.NET MVC快速入門之完整示例(MVC5+EF6)html

【番外篇】ASP.NET MVC快速入門之免費jQuery控件庫(MVC5+EF6)前端

 

FineUIMvc簡介

FineUIMvc 是基於 jQuery 的專業 ASP.NET MVC 控件庫,其前身是基於 WebForms 的開源控件庫 FineUI(歷時9120多個版本)。FineUIMvc(基礎版)包含開源版的所有功能,支持 30 種內置主題和 FontAwesome 圖標,支持消息對話框和單元格編輯表格,功能強大,最重要的是徹底免費java

 

如下引自FineUI官網的介紹:web

FineUIMvc(基礎版)做爲三石奉獻給社區的一個禮物,功能絕對強大到讓你心動:數據庫

1.       擁有 FineUI(開源版)的所有功能。bootstrap

2.       擁有 FineUI(專業版)相同的 jQuery 前端庫,體積小,速度快。數組

3.       擁有 FineUIMvc(企業版)強大的通知對話框和單元格編輯表格。

4.       內置 30 Metro jQueryUI 主題(以及自定義主題Bootstrap Pure)。

5.       內置 500 多個 FontAwesome 圖標字體,控件原生支持。

6.       9 年技術積累,1300 多位捐贈會員,100 多家企業客戶,穩定可信賴。

7.       重要的事情說三遍:徹底免費!徹底免費!徹底免費!

 

官網首頁:http://fineui.com/mvc/
在線示例:http://fineui.com/demo_mvc/

 

這篇文章,咱們將使用FineUIMvc(基礎版)來實現本示例。

 

FineUIMvc空項目

登陸FineUI的論壇,下載FineUIMvc空項目,這樣不只省去了配置的麻煩,並且還有默認的左右框架的實現:

http://fineui.com/bbs/forum.php?mod=viewthread&tid=9101

 

雙擊FineUIMvc.EmptyProject.sln,打開項目:

 

這個目錄結構和以前的很相似,多了一個res目錄,這個是FineUIMvc中的約定,用來放置靜態資源,好比CSSJS、圖片以及一套Icon圖標。

 

Ctrl+F5直接運行項目:

修改Web.config

空項目已經配置好了Web.config文件,主要是兩個地方的改動:

<configSections>

       <section name="FineUIMvc" type="FineUIMvc.ConfigSection, FineUIMvc"

requirePermission="false" />

</configSections>

<FineUIMvc DebugMode="true" Theme="Cupertino" />

 

 

這裏設置FineUIMvc的全局參數:

l  Theme: 樣式主題,內置 30 種主題(其中 6 Metro 主題,24 jQueryUI 官方主題,默認值:Default

n  Metro 主題:Default, Metro_Blue, Metro_Dark_Blue, Metro_Gray, Metro_Green, Metro_Orange

n  jQueryUI 主題: Black_Tie, Blitzer, Cupertino, Dark_Hive, Dot_Luv, Eggplant, Excite_Bike, Flick, Hot_Sneaks, Humanity, Le_Frog, Mint_Choc, Overcast, Pepper_Grinder, Redmond, Smoothness, South_Street, Start, Sunny, Swanky_Purse, Trontastic, UI_Darkness, UI_Lightness, Vader

l  CustomTheme: 自定義樣式主題(custom_default/bootstrap_pure

l  Language: 控件語言(en/zh_CN/zh_TW,默認值:zh_CN

l  FormMessageTarget: 表單字段錯誤提示信息的顯示位置(Title/Side/Qtip,默認值:Side

l  FormLabelWidth: 表單字段標籤的寬度(默認值:100px

l  FormLabelAlign: 表單字段標籤的位置(Left/Right/Top,默認值:Left

l  FormRedStarPosition: 表單字段紅色星號的位置(AfterText/BeforeText/AfterSeparator,默認值:AfterText

l  FormLabelSeparator: 表單字段標籤與內容的分隔符(默認值:""

l  EnableAjax: 是否啓用AJAX(默認值:true

l  AjaxTimeout: Ajax超時時間(單位:秒,默認值:120s

l  DebugMode: 是否開發模式,啓用時格式化頁面輸出的JavaScript代碼,便於調試(默認值:false

l  EnableAjaxLoading: 是否啓用Ajax提示(默認值:true

l  AjaxLoadingType: Ajax提示類型,默認在頁面頂部顯示黃色提示框(Default/Mask,默認值:Default

l  EnableShim: 是否啓用遮罩層,防止ActiveXFlash等對象覆蓋彈出窗體(默認值:false

l  EnableCompactMode: 是否啓用緊湊模式(默認值:false

l  EnableLargeMode: 是否啓用大字體模式(默認值:false

l  MobileAdaption: 是否啓用移動瀏覽器自適應(默認值:false

l  EnableAnimation: 是否啓用動畫(僅Webkit瀏覽器支持動畫效果)(默認值:false

l  LoadingImageNumber: 頁面加載動畫圖片的序號(從 1 30,默認值:1

 

更詳細的介紹參考FineUIMvc在線示例站點:

http://mvc.fineui.com/#/Config/ModifyWebConfig

 

另一處配置HTTP處理器:

<system.web>

       <httpModules>

         <add name="FineUIMvcScriptModule" type="FineUIMvc.ScriptModule, FineUIMvc"/>

       </httpModules>

       <httpHandlers>

         <add verb="GET" path="res.axd" type="FineUIMvc.ResourceHandler, FineUIMvc"/>

       </httpHandlers>

</system.web>

 

 

若是你以前用過FineUI(開源版),相信對這個配置很熟悉。

添加全局模型綁定器

Global.asax中,添加所有模型綁定器:

protected void Application_Start()
{
       AreaRegistration.RegisterAllAreas();
       FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
       RouteConfig.RegisterRoutes(RouteTable.Routes);

       ModelBinders.Binders.Add(typeof(JArray), new JArrayModelBinder()); ModelBinders.Binders.Add(typeof(JObject), new JObjectModelBinder());
}

 

 

這個設置用於模型綁定,能夠將客戶端傳入的JSON數組自動轉化爲JArray對象,相似以下代碼:

 

固然這個設置不是必須的,若是去掉這個設置,則上面的代碼就須要這樣寫了:

public ActionResult Grid1_PageIndexChanged(string Grid1_fields, int Grid1_pageIndex)
{
       JArray fields = JArray.Parse(Grid1_fields);

       // .....
}

 

 

佈局視圖

佈局視圖相似於WebForms的母版頁,位於Views/Home/Shared/_Layout.cshtml,咱們先看下其中的代碼:

@{
    var F = Html.F();
}
 
<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title - FineUIMvc 空項目</title>
 
    @F.RenderCss()
    <link href="~/res/css/common.css" rel="stylesheet" type="text/css" />
    @RenderSection("head", false)
 
</head>
<body>
    @Html.AntiForgeryToken()
 
    @F.PageManager
 
    @RenderSection("body", true)
 
    @F.RenderScript()
    @RenderSection("script", false)
 
</body>
</html>

 

 

總體架構很是簡單,其中和FineUIMvc密切相關的代碼:

1.     var F = Html.F():實例化FineUIMvcHTML輔助方法,視圖中全部的FineUIMvc控件都要經過F變量來初始化。

2.     F.RenderCss():放置FineUIMvc內置的CSS文件。

3.     F.PageManagerFineUIMvc的頁面管理器,每一個頁面都須要,因此放到佈局視圖中。

4.     F.RenderScript():放置FineUIMvc內置的JavaScript文件。

 

除此以外,咱們還經過MVC內置的RenderSection函數定義了幾個段落,主要用於放置自定義CSS文件,頁面主體HTML以及頁面自定義JavaScript腳本文件。

 

Html.AntiForgeryToken()用於防止跨站請求僞造攻擊,須要配合控制器中方法的[ValidateAntiForgeryToken]特性使用,本系列的第三篇文章曾作過詳細的介紹。

 

注意:和用VS自動生成的佈局視圖有一個很大的不一樣,這裏使用RenderSection("body", true)來方式主體HTML,第二個參數true代表這是一個必選項。因此在具體的視圖頁面,必須存在名爲body的節,不然就會報錯。

 

首頁視圖

首頁視圖的代碼相對有點複雜,從截圖上能夠看出,整個頁面被分爲三部分,上半部分放置網址標題,操做按鈕等控件,左側部分是一個樹控件,右側部分是一個選項卡控件,咱們先來看這部分的代碼:

@(F.RegionPanel()
       .ID("RegionPanel1")
       .ShowBorder(false)
       .IsViewPort(true)
       .Regions(
              F.Region()
                     .ID("Region1")
                     .ShowBorder(false)
                     .ShowHeader(false)
                     .RegionPosition(Position.Top)
                     .Layout(LayoutType.Fit)
                     .ContentEl("#header"),
              F.Region()
                     .ID("Region2")
                     .RegionSplit(true)
                     .Width(200)
                     .ShowHeader(true)
                     .Title("菜單")
                     .EnableCollapse(true)
                     .Layout(LayoutType.Fit)
                     .RegionPosition(Position.Left)
                     .Items(
                            F.Tree()
                                   .ShowBorder(false)
                                   .ShowHeader(false)
                                   .ID("treeMenu")
                                   .Nodes(
                                          F.TreeNode()
                                                 .Text("默認分類")
                                                 .Expanded(true)
                                                 .Nodes(
                                                        F.TreeNode()
                                                               .Text("開始頁面")
                                                               .NavigateUrl("~/Home/Hello"),
                                                        F.TreeNode()
                                                               .Text("登陸頁面")
                                                               .NavigateUrl("~/Home/Login")
                                                 )
                                   )
                     ),
              F.Region()
                     .ID("mainRegion")
                     .ShowHeader(false)
                     .Layout(LayoutType.Fit)
                     .RegionPosition(Position.Center)
                     .Items(
                            F.TabStrip()
                                   .ID("mainTabStrip")
                                   .EnableTabCloseMenu(true)
                                   .ShowBorder(false)
                                   .Tabs(
                                          F.Tab()
                                                 .ID("Tab1")
                                                 .Title("首頁")
                                                 .BodyPadding(10)
                                                 .Layout(LayoutType.Fit)
                                                 .Icon(Icon.House)
                                                 .ContentEl("#maincontent")
                                   )
                     )
       )
)

 

 

最外層是一個RegionPanel控件,並設置了填充整個瀏覽器窗口(IsViewPort=true),上半部分的Region控件經過ContentEl屬性來指定一個id=headerHTML片斷;左側Region裏面放置了一個硬編碼的Tree控件,經過指定RegionLayout=Fit來讓Tree控件填充整個左側區域;右側Region裏面放置了TabStrip控件,TabStrip放置了一個初始選項卡Tab,並經過ContentEl來指向一個id=maincontentHTML片斷。

 

這個分析過程也很容易理解,若是你以前使用過FineUI(開源版),對比應該並不陌生,只不過把以前的ASPX語法換成了Rezor語法而已。

 

左側樹控件和右側選項卡控件的交互是由JavaScript代碼控制的,這個常見交互FineUIMvc進行了封裝:

@section script {
    <script>
        // 頁面控件初始化完畢後,會調用用戶自定義的onReady函數
        F.ready(function () {
 
            // 初始化主框架中的樹和選項卡互動,以及地址欄的更新
            // treeMenu: 主框架中的樹控件實例
            // mainTabStrip: 選項卡實例
            // updateHash: 切換Tab時,是否更新地址欄Hash值(默認值:true)
            // refreshWhenExist: 添加選項卡時,若是選項卡已經存在,是否刷新內部IFrame(默認值:false)
            // refreshWhenTabChange: 切換選項卡時,是否刷新內部IFrame(默認值:false)
            // maxTabCount: 最大容許打開的選項卡數量
            // maxTabMessage: 超過最大容許打開選項卡數量時的提示信息
            F.initTreeTabStrip(F.ui.treeMenu, F.ui.mainTabStrip, {
                maxTabCount: 10,
                maxTabMessage: '請先關閉一些選項卡(最多容許打開 10 個)!'
            });
 
        });
    </script>
}

 

 

對這裏出現JavaScript代碼的簡單描述:

1.     F.ready:在控件初始化完畢後執行,相似於jQuery$.ready,只不過F.ready是在DomReady以後執行的。

2.     F.initTreeTabStrip:設置樹控件和選項卡控件的交互,點擊樹控件節點新建一個啓用IFrame的選項卡控件。裏面有不少參數能夠控制交互行爲,在上面的代碼中都有註釋,就不一一解釋了。

3.     F.ui.treeMenu:引用左側樹控件實例。FineUIMvc會在F.ui命名控件下存儲全部頁面上初始化的FineUIMvc控件,所以能夠方便的經過控件的名稱來引用。

 

主題選擇框

這個頁面還有一個須要JavaScript腳本的交互過程,那就是頁面右上角的[主體倉庫]按鈕,點擊此按鈕時會彈出一個啓用IFrameWindow控件,默認這個Window控件是隱藏的:

@(F.Window()
       .Hidden(true)
       .EnableResize(true)
       .EnableMaximize(true)
       .EnableClose(true)
       .Height(600)
       .Width(1020)
       .IsModal(true)
       .ClearIFrameAfterClose(false)
       .IFrameUrl(Url.Content("~/Home/Themes"))
       .EnableIFrame(true)
       .Title("主題倉庫")
       .ID("windowThemeRoller")
)

 

 

按鈕的代碼放置在id=headerHTML片斷中:

@(F.Button()
       .EnableDefaultCorner(false)
       .EnableDefaultState(false)
       .IconFont(IconFont.Bank)
       .IconAlign(IconAlign.Top)
       .Text("主題倉庫")
       .ID("btnThemeSelect")
       .CssClass("icontopaction themes")
       .Listener("click", "onThemeSelectClick")
)

 

 

經過ButtonListener屬性來指定點擊按鈕時須要執行的JavaScript腳本:

// 點擊主題倉庫
function onThemeSelectClick(event) {
       F.ui.windowThemeRoller.show();
}

 

 

 

選擇某個主題後的邏輯也很簡單,把用戶選擇的值保存到Cookie中而後刷新頁面,這個邏輯不難,請自行查看源代碼。

 

頁面刷新後,如何從Cookie中讀取值並設置所需的主題呢?這個邏輯實際上是在佈局視圖中完成的,下面來看下完整的佈局視圖:

@{
    var F = Html.F();
}
 
<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title - FineUIMvc 空項目</title>
 
    @F.RenderCss()
    <link href="~/res/css/common.css" rel="stylesheet" type="text/css" />
    @RenderSection("head", false)
 
</head>
<body>
    @Html.AntiForgeryToken()
 
    @{
        var pm = F.PageManager;
 
        // 主題
        HttpCookie themeCookie = Request.Cookies["Theme_Mvc"];
        if (themeCookie != null)
        {
            string themeValue = themeCookie.Value;
            Theme theme;
            if (Enum.TryParse<Theme>(themeValue, true, out theme))
            {
                            pm.CustomTheme(String.Empty);
                pm.Theme(theme);
            }
            else
            {
                pm.CustomTheme(themeValue);
            }
        }
    }
    @F.PageManager
 
    @RenderSection("body", true)
 
    @F.RenderScript()
    @RenderSection("script", false)
 
</body>
</html>

 

 

這個邏輯不難,首先從請求的HTTP參數中讀取須要的Cookie值,而後設置PageManagerTheme屬性,這裏之因此有個Enum.TryParse的邏輯,是由於Cookie中保存的也多是用戶自定義主題,二者的處理不一樣。

 

登陸頁面

1.     訪問學生列表頁面,會要求用戶先登陸,若是直接在瀏覽器地址欄輸入:

http://localhost:64475/Students

2.     頁面會被重定向到:http://localhost:64475/Login?ReturnUrl=%2fStudents

 

3.     登陸成功後,頁面會重定向到首頁:

 

4.     此時點擊用戶頭像的下拉菜單項[安全退出],就會重定向到登陸頁面。

 

 

這一系列過程是經過表單身份驗證完整的,先來看下登陸頁面的視圖代碼:

@{
    ViewBag.Title = "Login";
    var F = @Html.F();
}
 
@section body {
    @(F.Window()
        .Width(350)
        .WindowPosition(WindowPosition.GoldenSection)
        .EnableClose(false)
        .IsModal(false)
        .Title("登陸表單")
        .ID("Window1")
        .Items(
            F.SimpleForm()
                .ShowHeader(false)
                .LabelWidth(80)
                .BodyPadding(10)
                .ShowBorder(false)
                .ID("SimpleForm1")
                .Items(
                    F.TextBox()
                        .ShowRedStar(true)
                        .Required(true)
                        .Label("用戶名")
                        .ID("tbxUserName"),
                    F.TextBox()
                        .ShowRedStar(true)
                        .Required(true)
                        .TextMode(TextMode.Password)
                        .Label("密碼")
                        .ID("tbxPassword")
                )
        )
        .Toolbars(
            F.Toolbar()
                .Position(ToolbarPosition.Bottom)
                .ToolbarAlign(ToolbarAlign.Right)
                .ID("Toolbar1")
                .Items(
                    F.Button()
                        .OnClick(Url.Action("btnLogin_Click"), "SimpleForm1")
                        .ValidateTarget(Target.Top)
                        .ValidateForms("SimpleForm1")
                        .Type(ButtonType.Submit)
                        .Text("登陸")
                        .ID("btnLogin"),
                    F.Button()
                        .Type(ButtonType.Reset)
                        .Text("重置")
                        .ID("btnReset")
                )
        )
    )
}

 

 

這個頁面是由幾個FineUIMvc控件組成的:

1.     Window控件:默認彈出的Window控件位於頁面的中央位置。

2.     Toolbar控件:Window控件的底部工具欄。

3.     Button控件:工具欄中的[登陸][重置]按鈕。

4.     TextBox控件:[用戶名][密碼]文本輸入框。

 

點擊[登陸]按鈕,發起一個HTTP POST請求,這個請求對應於控制器LoginbtnLogin_Click方法,第二個參數SimpleForm1用於指定用於傳入控制器方法的表單參數。

 

這個過程對於WebForms開發者來講應該很面熟,若是用WebForms的術語我能夠這麼來講:點擊[登陸]按鈕,回發當前頁面,觸發後臺的btnLogin_Click事件。這裏我特意保留了WebForms中後臺事件的命名方法,其實換湯不換藥,百變不離其宗,瞭解HTTP協議的大概工做原理,就不難理解。

 

後臺的btnLogin_Click方法:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult btnLogin_Click(string tbxUserName, string tbxPassword)
{
       if (tbxUserName == "admin" && tbxPassword == "admin")
       {
              FormsAuthentication.RedirectFromLoginPage(tbxUserName, false);
       }
       else
       {
              ShowNotify("用戶名或密碼錯誤!", MessageBoxIcon.Error);
       }
 
       return UIHelper.Result();
}

 

 

退出操做:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult onSignOut_Click()
{
       FormsAuthentication.SignOut();
       return RedirectToAction("Index", "Login");
}

 

 

學生列表頁面(CRUD

FineUIMvc中全部去往服務器的POST請求都是AJAX,因此咱們能夠絕不費力的製做單頁應用程序。配合FineUIMvc內置的IFrame支持,能夠將一些邏輯獨立成一個頁面,不只有助於代碼的解耦,並且頁面效果也比較統一。

 

學生列表首頁:

 

在這個頁面中,咱們能夠進行以下操做:

1.     新增用戶:彈出一個啓用IFrameWindow控件,在新頁面中進行新增用戶操做,操做結束後,須要從新綁定表格數據(由於數據已經改變了)。

2.     編輯用戶:和新增是相似的邏輯。

3.     刪除單個用戶:在表格行中集成了刪除按鈕,刪除以前會有確認提示框。

4.     刪除多個用戶:點擊表格工具欄中的[刪除選中記錄],能夠一次刪除多條記錄,一樣刪除以前會有確認提示框。

 

表格頁面

咱們先來看下錶格的視圖代碼:

@(F.Grid()
       .IsViewPort(true)
       .ShowHeader(false)
       .ShowBorder(false)
       .ID("Grid1")
       .DataIDField("ID")
       .DataTextField("Name")
       .EnableCheckBoxSelect(true)
       .Toolbars(
              F.Toolbar()
                     .Items(
                            F.Button()
                                   .ID("btnDeleteSelected")
                                   .Icon(Icon.Delete)
                                   .Text("刪除選中記錄")
                                   .Listener("click", "onDeleteSelectedClick"),
                            F.ToolbarFill(),
                            F.Button()
                                   .ID("btnCreate")
                                   .Icon(Icon.Add)
                                   .Text("新增用戶")
                                   .Listener("click", "onCreateClick")
                     )
       )
       .Columns(
              F.RowNumberField(),
              F.RenderField()
                     .HeaderText("姓名")
                     .DataField("Name")
                     .Width(100),
              F.RenderField()
                     .HeaderText("性別")
                     .DataField("Gender")
                     .FieldType(FieldType.Int)
                     .RendererFunction("renderGender")
                     .Width(80),
              F.RenderField()
                     .HeaderText("所學專業")
                     .DataField("Major")
                     .ExpandUnusedSpace(true),
              F.RenderField()
                     .HeaderText("入學日期")
                     .DataField("EntranceDate")
                     .FieldType(FieldType.Date)
                     .Renderer(Renderer.Date)
                     .RendererArgument("yyyy-MM-dd")
                     .Width(100),
              F.RenderField()
                     .HeaderText("")
                     .Width(60)
                     .RendererFunction("renderEditField")
                     .TextAlign(TextAlign.Center)
                     .EnableHeaderMenu(false),
              F.RenderField()
                     .HeaderText("")
                     .Width(60)
                     .RendererFunction("renderDeleteField")
                     .TextAlign(TextAlign.Center)
                     .EnableHeaderMenu(false)
       )
       .DataSource(Model)
)

 

 

這裏除了對錶格列的定義以外,就是表格頂部工具欄的定義,裏面包含圖示的兩個操做按鈕。

 

表格數據是經過DataSource方法指定的,傳入的Model參數類型在頁面頭部有定義:

@model IEnumerable<FineUIMvc.QuickStart.Models.Student>

 

行渲染函數RendererFunction

同時注意性別列和表格最後的兩個操做列,都定義了RendererFunction方法,它用來指定列的客戶端渲染腳本。對於性別列,咱們知道其數據類型爲int,因此須要經過客戶端渲染函數來轉換爲字符串:

function renderGender(value, params) {
       return value == 1 ? '男' : '女';
}

 

 

而兩個操做列,則須要返回包含編輯和刪除圖標的HTML片斷:

function renderDeleteField(value, params) {
       return '<a href="javascript:;" class="deletefield">
<img class="f-grid-cell-icon" src="@Url.Content("~/res/icon/delete.png")"></a>';
}
 
function renderEditField(value, params) {
       return '<a href="javascript:;" class="editfield">
<img class="f-grid-cell-icon" src="@Url.Content("~/res/icon/pencil.png")"></a>';
}

 

 

行中刪除圖標的點擊事件

下面看下如何在腳本中處理行中的編輯圖標和刪除圖標的點擊事件:

F.ready(function () {
 
       var grid1 = F.ui.Grid1;
 
       grid1.el.on('click', 'a.deletefield', function (event) {
              var rowEl = $(this).closest('.f-grid-row');
              var rowData = grid1.getRowData(rowEl);
 
              F.confirm({
                     message: '你肯定要刪除選中的行數據嗎?',
                     target: '_top',
                     ok: function () {
                            deleteSelectedRows([rowData.id]);
                     }
              });
       });
});
 

 

 

首先經過F.ui.Grid1來獲取頁面上表格的實例,而F.ui.Grid1.el則是一個標準的jQuery對象,表示此表格在頁面上的DOM元素。而後經過jQueryon函數來註冊編輯圖標和刪除圖標的點擊事件。

 

在刪除事件中,經過jQueryclosest函數獲取編輯圖標所在的表格行,而後調用表格的getRowData方法獲取行數據,刪除時須要知道本行的行ID。而後調用F.confirm彈出確認對話框,在用戶點擊確認對話框的確認按鈕時,執行刪除操做(deleteSelectedRows函數)。

 

之因此將刪除邏輯放到deleteSelectedRows中,是由於在批量刪除時也須要用到,因此提取爲公共方法:

function deleteSelectedRows(selectedRows) {
       // 觸發後臺事件
       F.doPostBack('@Url.Action("Grid1_Delete")', {
              'selectedRows': selectedRows,
              'Grid1_fields': F.ui.Grid1.fields
       });
}

 

 

這裏調用了FineUIMvc封裝好的AJAX POST方法F.doPostBack(相似於WebForms中的__doPostBack的命名),第一個參數指定了請求的URL,第二個參數指定請求中附加的表單參數。

 

行中編輯圖標的點擊事件

因爲須要在Window控件中彈出新增用戶頁面和編輯用戶頁面,因此咱們還須要一個隱藏的Window控件:

@(F.Window()
       .ID("Window1")
       .Width(600)
       .Height(300)
       .IsModal(true)
       .Hidden(true)
       .Target(Target.Top)
       .EnableResize(true)
       .EnableMaximize(true)
       .EnableIFrame(true)
       .IFrameUrl(Url.Content("about:blank"))
       .OnClose(Url.Action("Window1_Close"), "Grid1")
)

 

 

注意:咱們爲Window控制設置Target=Top屬性,代表在頂層頁面中彈出這個窗體,而不是侷限在當前頁面內,這個是FineUIMvc內置的特性,而且僅對於啓用IFrameWindow窗體有效(EnableIFrame)。

 

 

F.ready函數中註冊編輯圖標的點擊事件:

grid1.el.on('click', 'a.editfield', function (event) {
       var rowEl = $(this).closest('.f-grid-row');
       var rowData = grid1.getRowData(rowEl);
 
       F.ui.Window1.show('@Url.Content("~/Students/Edit/")?studentId=' + rowData.id, '編輯用戶');
});

 

 

在編輯事件中,一樣先取得當前行數據,而後調用F.ui.Window1.show來在Window控件中顯示編輯頁面,第二個參數[編輯用戶]指定Window控件的標題欄文本。

 

 

編輯窗體中的[保存後關閉]按鈕邏輯

先來看下Edit視圖代碼:

@{
    ViewBag.Title = "Edit";
    var F = @Html.F();
}
 
@model FineUIMvc.QuickStart.Models.Student
 
@section body {
    @(F.Panel()
        .ID("Panel1")
        .ShowBorder(false)
        .ShowHeader(false)
        .BodyPadding(10)
        .AutoScroll(true)
        .IsViewPort(true)
        .Toolbars(
            F.Toolbar()
                .Items(
                    F.Button()
                        .Icon(Icon.SystemClose)
                        .Text("關閉")
                        .Listener("click", "F.activeWindow.hide();"),
                    F.ToolbarSeparator(),
                    F.Button()
                        .ValidateForms("SimpleForm1")
                        .Icon(Icon.SystemSaveClose)
                        .OnClick(Url.Action("btnEdit_Click"), "SimpleForm1")
                        .Text("保存後關閉")
                )
        )
        .Items(
            F.SimpleForm()
                .ID("SimpleForm1")
                .ShowBorder(false)
                .ShowHeader(false)
                .Items(
                    F.HiddenFieldFor(m => m.ID),
                    F.TextBoxFor(m => m.Name),
                    F.RadioButtonListFor(m => m.Gender)
                        .Items(
                            F.RadioItem()
                                .Text("")
                                .Value("1"),
                            F.RadioItem()
                                .Text("")
                                .Value("0")
                        ),
                    F.TextBoxFor(m => m.Major),
                    F.DatePickerFor(m => m.EntranceDate)
                        .EnableEdit(false)
                )
        )
    )
}
 

 

讓咱們把關注點轉移到兩個操做按鈕:

1.     [關閉]按鈕:Listener("click", "F.activeWindow.hide();"),經過這種方式註冊一段JavaScript腳本,用來關閉當前IFrame所在的活動窗體。

2.     [保存後關閉]按鈕:這個邏輯要在服務器端處理,由於咱們須要先在服務器端保存數據到數據庫,而後才能關閉當前活動窗體。

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult btnEdit_Click([Bind(Include = "ID,Name,Gender,Major,EntranceDate")] Student student)
{
       if (ModelState.IsValid)
       {
              db.Entry(student).State = EntityState.Modified;
              db.SaveChanges();
 
              // 關閉本窗體(觸發窗體的關閉事件)
PageContext.RegisterStartupScript(ActiveWindow.GetHidePostBackReference());
       }
 
       return UIHelper.Result();
}

 

 

關閉活動窗體的邏輯是經過PageContext.RegisterStartupScript函數來註冊一段JavaScript腳原本完成的,若是你以前使用過FineUI(開源版),詳細對此函數必定很是熟悉:

1.     ActiveWindow表明的是當前活動的Window控件,而當前腳本是在Window控件的IFrame頁面內執行的。

2.     GetHidePostBackReference用於獲取一段腳本,首先關閉當前活動的Window控件,而後觸發Window控件的Close事件。這裏的命名和開源版中的命名如出一轍,相信你不會陌生。

 

刪除多行記錄

表格工具欄中有一個[刪除選中記錄]按鈕,用戶能夠經過Ctrl或者Shift選擇多行,而後點擊刪除:

 

這個彈出確認框的邏輯是在客戶端完成的,若是默認沒有選中值,則會彈出另外一個提示框:

 

首先在視圖中經過Listener屬性來註冊按鈕的客戶端腳本處理函數:

F.Button()
       .ID("btnDeleteSelected")
       .Icon(Icon.Delete)
       .Text("刪除選中記錄")
       .Listener("click", "onDeleteSelectedClick")

 

 

下面看下這個腳本處理函數:

function onDeleteSelectedClick(event) {
       var grid1 = F.ui.Grid1;
 
       if (!grid1.hasSelection()) {
              F.alert('請至少選擇一項!');
              return;
       }
 
       var selectedRows = grid1.getSelectedRows();
       F.confirm({
              message: '你肯定要刪除選中的&nbsp;<b>' + selectedRows.length + '</b>&nbsp;行數據嗎?',
              target: '_top',
              ok: function () {
                     deleteSelectedRows(selectedRows);
              }
       });
}

 

 

這裏有對FineUIMvc的客戶端API接口的調用:

1.     hasSelection:返回表格是否有選中行。

2.     F.alert:用來彈出一個提示框。

3.     getSelectedRows:返回表格選中的行數組,數組元素是行的ID(在表格定義中經過DataIDField標識),這個函數還有個重載,若是傳入true參數,則返回的表格元素爲行數據。

4.     F.confirm:用來彈出一個確認框,target用來指定的彈出的位置,因爲當前頁面位於iframe中,因此咱們但願在頂層窗口中彈出確認框。

 

表單檢索與數據庫分頁

限於篇幅緣由,表單檢索和數據庫分頁就不講解了,請自行查看源代碼。

 

小結

本示例使用FineUIMvc(基礎版)來實現相同的示例功能,可是頁面效果更加專業,功能更加完善,全部到服務器的POST請求都是AJAX,而IFrame的內置支持讓整個頁面交互輕鬆天然,不用跳來跳去,同時又能保持業務邏輯代碼的獨立,方便維護更新。

下載示例源代碼

相關文章
相關標籤/搜索