本文章是由機器翻譯。

ASP.NET MVC 5

單頁應用程式的 .NET 開發人員入門

Long Le

下载代码示例

大多數 Microsoft.NET 框架開發人員花了他們職業生涯的大部分在伺服器端,編碼的 C# 或Visual Basic的.NET 構建 Web 應用程式時。當然,JavaScript 已經被用於模態視窗、 驗證、 AJAX 調用等簡單的事情,等等。然而,已作為一種實用程式語言,利用了 JavaScript (在多數情況下的用戶端代碼),應用程式就很大程度上被逐出的伺服器端。

最近已遷移從伺服器端到用戶端 (瀏覽器) 來滿足使用者的期望為流體和反應迅速的使用者體驗的 Web 應用程式代碼的一大趨勢與這種情況下,大量的.NET 開發人員 (尤其是在企業) 在處理關於 JavaScript 的最佳做法、 體系結構、 單元測試、 可維護性和近期的不同種類的 JavaScript 庫極大的焦慮。部分移動到用戶端是趨勢的越來越多地使用單頁面應用程式 (Spa)。說 SPA 發展是未來是一個極端保守。Spa 水療中心是如何在 Web 上的最佳應用程式的一些提供流體 UX 和回應能力,同時最小化 (交通) 的有效載荷和到伺服器的往返過程。

在本文中,我會解決您可能會遇到進行轉換時,從伺服器端到 SPA 的領土的憂慮。最佳的方式來處理這些憂慮是擁抱 JavaScript 作為一流的語言就像任何.NET 語言,如 C# 中,Visual Basic的.NET,Python,等等。

以下是.NET 開發,有時會忽略或忘記開發在 JavaScript 中的應用程式時的一些基本原則:

  • 您的基本代碼是在.NET 中易於管理,因為你是決定性與班級界限和類實際上住在您的專案的範圍內。
  • 你單獨關注的問題,所以您不必負責為數百個不同的東西與責任重疊的類。
  • 你有可重複使用的存儲庫、 查詢、 實體 (模型) 和資料來源。
  • 你可以投入一些思想命名您的類和檔,這樣他們就更有意義。
  • 你練習好使用的設計模式,編碼公約和組織。

因為這篇文章是對於.NET 開發人員被被引進到溫泉世界,我會將納入最少數量的框架可以生成帶有聲音體系結構易於管理的水療中心。

在七個關鍵步驟中創建一個水療中心

以下是七個關鍵步驟,將進入 SPA (與適當的專案檔案可以在附帶的代碼下載中找到引用) 用外框Visual Studio2013ASP.NETMVC 範本創建的新ASP.NETWeb 應用程式轉換。

  1. 下載並安裝 NuGet 包 RequireJS,RequireJS 文字外掛程式和劍道 UI 網站。
  2. 添加一個配置模組 (Northwind.Web/Scripts/app/main.js)。
  3. 添加應用模組 (Northwind.Web/Scripts/app/app.js)。
  4. 添加一個路由器模組 (Northwind.Web/Scripts/app/router.js)。
  5. 添加的操作並查看這兩個命名的 Spa (Northwind.Web/Controllers/HomeController.cs 和 Northwind.Web/Views/Home/Spa.cshtml)。
  6. 修改 _ViewStart.cshtml 檔,所以 MVC 將載入視圖,而無需使用的 _Layout.cshtml 檔,預設情況下 (Northwind.Web/Views/_ViewStart.cshtml)。
  7. 更新的佈局 (功能表) 導航連結,以匹配新的水療中心友好網址 (Northwind.Web/Views/Shared/_Layout.cshtml)。

以下七個步驟進行了後,您的 Web 應用程式專案結構看起來應像圖 1


圖 1ASP.NETMVC 專案結構

我將展示如何構建與以下的 JavaScript 庫,可通過 NuGetASP.NETMVC 中一個令人敬畏的水療中心:

  • RequireJS (requirejs.org):這是一個JAVA­指令檔和模組載入程式。RequireJS 將提供 #include/導入/需要的 Api,並且能夠載入嵌套使用依賴注入 (DI) 的依賴關係。RequireJS 的設計方法使用非同步模組定義 (AMD) 的 API 對於 JavaScript 模組,這有助於成有用的單位封裝的代碼片段。它還提供了直觀的方式來引用其他單位代碼 (模組)。RequireJS 模組也遵循模組模式 (bit.ly/18byc2Q)。這種模式的簡化的實現封裝使用 JavaScript 函數。你會看到這種模式在以後隨著所有 JavaScript 模組將都包裹"定義"需要"的職能範圍內的行動。
  • 那些熟悉 DI 和反演的控制 (國際奧會) 概念可以認為這作為用戶端的 DI 框架。如果這就是明確作為泥漿在時刻,無後顧之憂 — — 很快就到一些編碼的插圖,所有這一切才有意義。
  • 文本用於 RequireJS 的外掛程式 (bit.ly/1cd8lTZ):這將用於遠端載入到 spa 館的大塊的 HTML (視圖)。
  • Entity Framework(bit.ly/1bKiZ9I):這很好理解,和因為本文的重點是在溫泉上,我不會得到太多到Entity Framework。然而,如果你是新到這,有大量的檔可用。
  • 劍道 UI 網站 (bit.ly/t4VkVp):這是全面的 JavaScript /­HTML5 框架,包含 Web UI 視窗小部件、 資料來源、 範本、 模型-視圖-ViewModel (MVVM) 模式、 spa 水療中心、 造型,等等,説明提供一個反應與適應的應用程式,將會看起來很棒。

設置水療中心基礎結構

若要顯示如何設置的水療中心基礎設施,第一次我會解釋如何創建的 RequireJS (config) 模組 (Northwind.Web/Scripts/app/main.js)。本模組將 app 啟動進入點。如果您已經創建一個主控台應用程式,你可以認為這作為 Program.cs 中的主進入點。它基本上包含的第一個類和水療中心啟動時調用的方法。Main.js 檔基本上擔當 SPA 的清單,並且是在其中你會定義在溫泉的所有事情都都和它們的依賴項,如果有的話。RequireJS 配置的代碼所示圖 2

圖 2 RequireJS 配置

require.config({
  paths: {
    // Packages
    'jquery': '/scripts/jquery-2.0.3.min',
    'kendo': '/scripts/kendo/2013.3.1119/kendo.web.min',
    'text': '/scripts/text',
    'router': '/scripts/app/router'
  },
  shim : {
    'kendo' : ['jquery']
  },
  priority: ['text', 'router', 'app'],
  jquery: '2.0.3',
  waitSeconds: 30
});
require([
  'app'
], function (app) {
  app.initialize();
});

圖 2,路徑屬性包含的所有模組都所在的位置和它們的名稱的清單。Shim 是模組的以前定義的名稱。Shim 財產包括的模組可能具有的任何依賴項。在這種情況下,您正在載入一個名為劍道模組和它在一個名為 jquery 模組上有依賴項,因此如果一個模組需要劍道模組,去並載入 jQuery 第一,因為 jQuery 已被定義為劍道模組的依存關係。

圖 2,代碼"要求 ([] 中,function(){})"將會在下一個模組中,這是我名為應用程式的模組載入。請注意我故意給有意義的名稱的模組。

所以,您 SPA 知道如何來第一次調用此模組?你第一次在溫泉中的腳本的引用標記的資料主要屬性的著陸頁上配置這為 RequireJS。我已經指定它運行的主模組 (main.js)。RequireJS 將處理所有參與載入此模組 ; 重物 你只需要告訴它要第一次載入的模組。

你有兩個選項將載入到 SPA 的水療中心意見:標準 HTML (*.html) 或ASP.NETMVC 剃刀 (*.cshtml) 頁。因為這篇文章針對.NET 開發人員 — — 和很多企業都有伺服器端庫和框架他們想要繼續使用他們的意見 — — 我去與後者創建 Razor 視圖的選項。

我會通過添加一個視圖啟動並將其命名 Spa.cshtml,如前文所述。這種觀點基本上要載入 shell 或水療中心的佈局中的所有 HTML。從這一觀點,我就會載入在其他視圖 (例如,About.cshtml、 Contact.cshtml、 Index.cshtml 等等) 當使用者導航通過水療中心,通過交換替換在"內容"專區中的所有 HTML 的意見

創建 SPA 著陸頁 (佈局) (Northwind.Web/Views/Spa.cshtml) Spa.cshtml 視圖是水療中心的著陸頁哪裡你就會載入您所有其他視圖中,因為不會有很多標記在這裡,除了引用所需的樣式表和 RequireJS。請注意下面的代碼,告訴 RequireJS,第一次載入的模組中的資料主要屬性:

@{
  ViewBag.Title = "Spa";
  Layout = "~/Views/Shared/_Layout.cshtml";
}
<link href=
  "~/Content/kendo/2013.3.1119/kendo.common.min.css" 
  rel="stylesheet" />
<link href=
  "~/Content/kendo/2013.3.1119/kendo.bootstrap.min.css" 
  rel="stylesheet" />
<script src=
  "@Url.Content("~/scripts/require.js")"
  data-main="/scripts/app/main"></script>
<div id="app"></div>

將操作添加的水療中心佈局 (Northwind.Web/­Controllers/HomeController.cs) 要創建並載入 Spa.cshtml 視圖,添加一個操作和視圖:

public ActionResult Spa()
{
  return View();
}

創建應用程式的模組 (Northwind.Web/Scripts/app/app.js) 這裡是應用模組,負責初始化和啟動劍道 UI 路由器:

define([
    'router'
  ], function (router) {
    var initialize = function() {
      router.start();
    };
    return {
      initialize: initialize
    };
  });

創建路由器模組 (Northwind.Web/Scripts/app/router.js) 這由 app.js 調用。如果你已經熟悉ASP.NETMVC 路線,它是同樣的觀念。這些都是溫泉路線為您的意見。我會為所有水療中心意見所以當使用者導航通過水療中心,劍道 UI 路由器將知道什麼意見要載入到溫泉的定義的所有路由。請參閱上市 1 隨附下載中。

劍道 UI 路由器類負責跟蹤應用程式的狀態和應用程式狀態之間導航。路由器將集成到瀏覽器歷史記錄中使用的 URL (#page),使應用程式狀態,可以設置書簽和可連結的片段部分。當按一下一個可路由的 URL 時,路由器踢和告訴應用程式要將自己放回被編碼到路由的狀態。路由定義是表示用於標識使用者想要查看的應用程式的狀態路徑的字串。當從瀏覽器的 URL 雜湊片段匹配路由定義時,路由處理常式稱為 (見圖 3)。

圖 3 註冊路由定義和相應的 Url

註冊的路由 (定義) 實際全 (可以設置書簽) URL
/ localhost:25061/主頁/水療/家居/索引
/ 首頁/索引 localhost:25061/主頁/spa / #/ 主頁/索引/首頁/關於我們
/ 首頁/關於我們 localhost:25061/主頁/水療 / #/ 首頁/關於/首頁/聯繫我們
/ 首頁/聯繫我們 localhost:25061/主頁/水療 / # 首頁/連絡人客戶/索引
/ 客戶/索引 localhost:25061/主頁/水療 / #/ 客戶/索引

至於劍道 UI 佈局構件,其名稱是不言而喻的。您可能已經熟悉的ASP.NETWeb 表單 MasterPage 或 MVC 的佈局,包括在專案中創建一個新的ASP.NETMVC Web 應用程式時。在這個溫泉專案中,它位於 Northwind.Web/Views/Shared/_Layout.cshtml 的路徑。小之間沒有區別的劍道 UI 佈局和 MVC 的佈局,除了劍道 UI 佈局在用戶端上運行。只是作為工作在伺服器端,哪裡的 MVC 運行時需要換出的佈局與其他視圖,劍道 UI 佈局工程完全同樣的內容的佈局。你換出視圖 (內容) 使用 showIn 方法的劍道 UI 佈局。將在 id 為"內容",它在初始化時傳入的劍道 UI 佈局 div 放置視圖內容 (HTML)。初始化佈局之後, 你然後呈現在它裡面的 div id"app,"是一個 div,著陸頁 (Northwind.Web/Views/Home/Spa.cshtml) 中。我不久就會檢討的。

LoadView helper 方法採用在視圖模型中,一個視圖和 — — 如果需要 — — 回檔來調用視圖和視圖模型綁定一旦發生。在 loadView 方法中,您利用劍道 UI FX 圖書館,以審美加強 UX 向交換進程視圖添加一些簡單的動畫。這通過向左滑動當前裝載的視圖,在新視圖中遠端載入,然後滑動新載入的視圖回中心。很明顯,你可以輕鬆更改這到各種不同的動畫效果使用劍道 UI FX 庫。使用的劍道 UI 佈局的主要好處之一是顯示當您調用 showIn 方法要交換了意見。它將確保視圖是卸載、 正確銷毀和從瀏覽器的 DOM,從而確保水療中心可以縮放和是性能中刪除。

編輯檢視 _ViewStart.cshtml (Northwind.Web/Views/­_ViewStart.cshtml) 在這裡是如何配置為不使用ASP.NETMVC 佈局,預設情況下的所有視圖:

@{
  Layout = null;
}

此時,水療中心應該工作。當按一下的任何功能表上的導航連結,可以看到當前內容被交換出通過 AJAX 劍道 UI 路由器和 RequireJS。

這些新鮮ASP.NETWeb 應用程式轉換成一個水療中心所需的七個步驟不是太糟了,他們嗎?

現在,SPA 是向上和運行,我就會去做什麼大多數開發人員最終會做 SPA,添加一些創建、 讀取、 更新和刪除 (CRUD) 功能。

將 CRUD 功能添加到水療中心

這裡是客戶網格視圖添加到水療中心 (和相關的專案的代碼檔) 所需的關鍵步驟:

  • 添加一個 CustomerController MVC 控制器 (Northwind.Web/Controllers/CustomerController.cs)。
  • 添加一個休息 OData 客戶 Web API 控制器 (Northwind.Web/Api/CustomerController.cs)。
  • 添加客戶網格視圖 (Northwind.Web/Views/­Customer/Index.cshtml)。
  • 添加一個 CustomerModel 模組 (Northwind.Web/Scripts/app/models/CustomerModel)。
  • 添加一個用於客戶網格的 customerDatasource 模組 (Northwind.Web/Scripts/app/datasources/customer­Datasource.js)。
  • 添加 indexViewModel 模組的客戶網格視圖 (Northwind.Web/Scripts/app/viewModels/­indexViewModel.js)。

設置解決方案與Entity Framework結構圖 4 顯示的解決方案結構,高­照明三個專案:Northwind.Data (1)、 Northwind.Entity (2) 和 Northwind.Web (3)。我將簡要地討論每個,以及Entity Framework電源工具。

  • Northwind.Data:這包括一切有關的Entity Framework物件-關係映射 (ORM) 工具,持久性的。
  • Northwind.Entity:這包括域實體,組成的平原舊 CLR 物件 (POCO) 類。這些都是持久性無知域的所有物件。
  • Northwind.Web:這包括ASP.NETMVC 5 Web 應用程式的展示層,凡以前你會建造出與兩個溫泉
  • 提到圖書館 — — 劍道 UI 和 RequireJS — — 和其他伺服器端堆疊:Entity Framework、 Web API 和 OData。
  • Entity Framework電動工具:若要創建所有的 POCO 實體和映射 (資料庫-第一次),我使用的Entity Framework電源工具從Entity Framework團隊 (bit.ly/1cdobhk)。在代碼生成中後, 做在這裡是只是複製到一個單獨的專案 (Northwind.Entity) 的實體處理分離問題。


圖 4 最佳實踐解決方案結構

請注意:羅斯文 SQL 安裝腳本和資料庫的備份,包括在可下載的原始程式碼中的 Northwind.Web/App_Data 資料夾下 (bit.ly/1cph5qc)。

現在,該解決方案設置了訪問資料庫,我就會去和寫的 MVC CustomerController.cs 類提供索引視圖和編輯檢視。由於該控制器的唯一的責任是以 HTML 視圖和水療中心提供,此處的代碼將最小。

創建 MVC 客戶控制器 (Northwind.Web/­Controllers/CustomerController.cs) 在這裡是如何創建的客戶控制器以行動為索引視圖和編輯檢視:

public class CustomerController : Controller
{
  public ActionResult Index()
  {
    return View();
  }
  public ActionResult Edit()
  {
    return View();
  }
}

與客戶的網格創建視圖 (Northwind.Web/­Views/Customers/Index.cshtml) 圖 5 演示如何與客戶網格創建的視圖。

如果中的標記, 圖 5 不是熟悉的不要驚慌 — — 它是只是劍道 UI 使用 MVVM (HTML) 標記。 它只需配置一個 HTML 元素,在本例中 id 為 div 的"網格"。稍後當你將此視圖綁定到一個視圖模型與劍道 UI 使用 MVVM 框架,此標記將轉換為劍道 UI 視窗小部件。 你可以閱讀更多關於這在 bit.ly/1d2Bgfj

圖 5 客戶網格視圖標記與使用 MVVM 構件和事件綁定

<div class="demo-section">
  <div class="k-content" style="width: 100%">
    <div id="grid"
      data-role="grid"
      data-sortable="true"
      data-pageable="true"
      data-filterable="true"
      data-editable="inline"
      data-selectable="true"
      data-toolbar='[ { template: kendo.template($("#toolbar").html()) } ]'
      data-columns='[
        { field: "CustomerID", title: "ID", width: "75px" },
        { field: "CompanyName", title: "Company"},
        { field: "ContactName", title: "Contact" },
        { field: "ContactTitle", title: "Title" },
        { field: "Address" },
        { field: "City" },
        { field: "PostalCode" },
        { field: "Country" },
        { field: "Phone" },
        { field: "Fax" } ]'
      data-bind="source: dataSource, events:
        { change: onChange, dataBound: onDataBound }">
    </div>
    <style scoped>
    #grid .k-toolbar {
      padding: 15px;
    }
    .toolbar {
      float: right;
    }
    </style>
  </div>
</div>
<script type="text/x-kendo-template" id="toolbar">
  <div>
    <div class="toolbar">
      <span data-role="button" data-bind="click: edit">
        <span class="k-icon k-i-tick"></span>Edit</span>
      <span data-role="button" data-bind="click: destroy">
        <span class="k-icon k-i-tick"></span>Delete</span>
      <span data-role="button" data-bind="click: details">
        <span class="k-icon k-i-tick"></span>Edit Details</span>
    </div>
    <div class="toolbar" style="display:none">
      <span data-role="button" data-bind="click: save">
        <span class="k-icon k-i-tick"></span>Save</span>
      <span data-role="button" data-bind="click: cancel">
        <span class="k-icon k-i-tick"></span>Cancel</span>
    </div>
  </div>
</script>

創建 MVC (OData) Web API 客戶控制器 (Northwind.Web/Api/CustomerController.cs) 現在我將展示如何創建 MVC (OData) Web API 客戶控制器。 OData 是提供統一的方式來查詢和運算元據集的 CRUD 操作通過 Web 資料訪問協定。 使用ASP.NETWeb API,它很容易創建 OData 終結點。 您可以控制哪些 OData 操作被暴露。 你可以承載多個 OData 端點旁邊非 OData 端點。 你有你的資料模型、 後端的業務邏輯和資料層的完全控制。 圖 6 客戶 Web API OData 控制器顯示的代碼。

中的代碼圖 6 只是創建 OData Web API 控制器來公開從 Northwind 資料庫的客戶資料。 這創建後,您可以運行該專案,和用提琴手工具 (免費 Web 調試器在 fiddler2.com) 或 LINQPad,您實際上可以查詢客戶資料。

圖 6 客戶 Web API OData 控制器

public class CustomerController : EntitySetController<Customer, string>
{
  private readonly NorthwindContext _northwindContext;
  public CustomerController()
  {
    _northwindContext = new NorthwindContext();
  }
  public override IQueryable<Customer> Get()
  {
    return _northwindContext.Customers;
  }
  protected override Customer GetEntityByKey(string key)
  {
    return _northwindContext.Customers.Find(key);
  }
  protected override Customer UpdateEntity(string key, Customer update)
  {
    _northwindContext.Customers.AddOrUpdate(update);
    _northwindContext.SaveChanges();
    return update;
  }
  public override void Delete(string key)
  {
    var customer = _northwindContext.Customers.Find(key);
    _northwindContext.Customers.Remove(customer);
    _northwindContext.SaveChanges();
  }
}

配置和揭露 OData 從 Customer 表中的網格 (Northwind.Web/App_Start/WebApiConfig.cs) 圖 7 配置並公開 OData 從 Customer 表中的網格。

查詢 OData Web API 與 LINQPad 如果你還沒有使用 LINQPad (linqpad.net) 然而,請將該工具添加到您的開發人員工具組 ; 它是必須擁有的並且是免費的版本中可用。 圖 8 顯示 LINQPad 具有連接到 Web API OData (localhost:2501 / odata),顯示結果的LINQ查詢中,"Customer.Take (100)"。

圖 7 為 OData 配置ASP.NETMVC Web API 路線

public static void Register(HttpConfiguration config)
{
  // Web API configuration and services
  ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
  var customerEntitySetConfiguration =
    modelBuilder.EntitySet<Customer>("Customer");
  customerEntitySetConfiguration.EntityType.Ignore(t => t.Orders);
  customerEntitySetConfiguration.EntityType.Ignore(t =>
     t.CustomerDemographics);
  var model = modelBuilder.GetEdmModel();
  config.Routes.MapODataRoute("ODataRoute", "odata", model);
  config.EnableQuerySupport();
  // Web API routes
  config.MapHttpAttributeRoutes();
  config.Routes.MapHttpRoute(
    "DefaultApi", "api/{controller}/{id}",
    new {id = RouteParameter.Optional});
}


圖 8 查詢客戶控制器的 Web API OData 通過 LINQPad 查詢

創建 (可測) 客戶模型 (Northwind.Web/­Scripts/app/models/customerModel.js) 下一步創建 (劍道 UI 可測) 客戶模型。你可以認為這作為用戶端客戶實體域模型。我創建客戶模型,因此它可以方便地重用由客戶網格視圖和編輯檢視。程式碼如 [圖 9] 中所示。

圖 9 創建的客戶 (可測的劍道 UI) 模型

define(['kendo'],
  function (kendo) {
    var customerModel = kendo.data.Model.define({
      id: "CustomerID",
      fields: {
        CustomerID: { type: "string", editable: false, nullable: false },
        CompanyName: { title: "Company", type: "string" },
        ContactName: { title: "Contact", type: "string" },
        ContactTitle: { title: "Title", type: "string" },
        Address: { type: "string" },
        City: { type: "string" },
        PostalCode: { type: "string" },
        Country: { type: "string" },
        Phone: { type: "string" },
        Fax: { type: "string" },
        State: { type: "string" }
      }
    });
    return customerModel;
  });

為客戶網格 (Northwind.Web/Scripts/app/datasources/customersDatasource.js) 創建一個資料來源如果你熟悉從ASP.NETWeb 表單的資料來源,概念也一樣,在其中創建客戶網格 (Northwind.Web/Scripts/app/datasources/customersDatasource.js) 的資料來源。劍道 UI 資料來源 (bit.ly/1d0Ycvd) 元件是使用 (JavaScript 物件陣列) 的本地或遠端的 (XML、 JSON 或 JSONP) 資料的抽象。它完全支援資料的 CRUD 操作,並提供本地和伺服器端支援進行排序、 分頁、 篩選、 分組和聚合。

為客戶網格視圖創建視圖模型如果你熟悉使用 MVVM 從Windows Presentation Foundation(WPF) 或 Silverlight,這是同樣的確切概念,只是在用戶端上 (在這一專案在 Northwind.Web/Scripts/ViewModels/ 中找到­Customer/indexViewModel.cs)。使用 MVVM 是用於分隔的視圖和其資料和業務邏輯的建築分離模式。所有的資料、 業務邏輯和等等是視圖模型中,該視圖是純粹 HTML (演示文稿),您將看到在位。圖 10 為客戶網格視圖顯示的代碼。

圖 10 客戶網格視圖模型

define(['kendo', 'customerDatasource'],
  function (kendo, customerDatasource) {
    var lastSelectedDataItem = null;
    var onClick = function (event, delegate) {
      event.preventDefault();
      var grid = $("#grid").data("kendoGrid");
      var selectedRow = grid.select();
      var dataItem = grid.dataItem(selectedRow);
      if (selectedRow.length > 0)
        delegate(grid, selectedRow, dataItem);
      else
        alert("Please select a row.");
      };
      var indexViewModel = new kendo.data.ObservableObject({
        save: function (event) {
          onClick(event, function (grid) {
            grid.saveRow();
            $(".toolbar").toggle();
          });
        },
        cancel: function (event) {
          onClick(event, function (grid) {
            grid.cancelRow();
            $(".toolbar").toggle();
          });
        },
        details: function (event) {
          onClick(event, function (grid, row, dataItem) {
            router.
navigate('/customer/edit/' + dataItem.CustomerID);
          });
        },
        edit: function (event) {
          onClick(event, function (grid, row) {
            grid.editRow(row);
            $(".toolbar").toggle();
          });
        },
        destroy: function (event) {
          onClick(event, function (grid, row, dataItem) {
            grid.dataSource.remove(dataItem);
            grid.dataSource.sync();
          });
        },
        onChange: function (arg) {
          var grid = arg.sender;
          lastSelectedDataItem = grid.dataItem(grid.select());
        },
        dataSource: customerDatasource,
        onDataBound: function (arg) {
          // Check if a row was selected
          if (lastSelectedDataItem == null) return;
          // Get all the rows     
          var view = this.dataSource.view();
          // Iterate through rows
          for (var i = 0; i < view.length; i++) {
          // Find row with the lastSelectedProduct
            if (view[i].CustomerID == lastSelectedDataItem.CustomerID) {
              // Get the grid
              var grid = arg.sender;
              // Set the selected row
              grid.select(grid.table.find("tr[data-uid='" + view[i].uid + "']"));
              break;
            }
          }
        },
      });
      return indexViewModel;
  });

我將簡要地描述各種元件中的代碼的圖 10

  • onClick (傭工):此方法是一個 helper 函數,獲取的客戶網格、 當前選定的行和客戶的代表權的 JSON 模式實例所選行。
  • 保存:這做的客戶的內聯編輯時保存的更改。
  • 取消:這取消內聯編輯模式。
  • 詳細資訊:這會定位到編輯客戶視圖,水療中心,將客戶的 ID 追加到 URL。
  • 編輯:這會啟動內聯編輯當前所選客戶。
  • 銷毀:這將刪除當前所選的客戶。
  • onChange 事件 (事件):這將觸發每次選擇某個客戶。您存儲最後選定的客戶,所以你可以維護的狀態。後執行的任何更新或導航出客戶網格,當導航回你重新選擇最後一次的網格選擇客戶。

現在將 customerModel、 indexViewModel 和 customersDatasource 模組添加到您的 RequireJS 配置 (Northwind.Web/Scripts/app/main.js)。程式碼如 [圖 11] 中所示。

圖 11 RequireJS 配置增加

paths: {
  // Packages
  'jquery': '/scripts/jquery-2.0.3.min',
  'kendo': '/scripts/kendo/2013.3.1119/kendo.web.min',
  'text': '/scripts/text',
  'router': '/scripts/app/router',
  // Models
  'customerModel': '/scripts/app/models/customerModel',
  // View models
  'customer-indexViewModel': '/scripts/app/viewmodels/customer/indexViewModel',
  'customer-editViewModel': '/scripts/app/viewmodels/customer/editViewModel',
  // Data sources
  'customerDatasource': '/scripts/app/datasources/customerDatasource',
  // Utils
  'util': '/scripts/util'
}

為新客戶網格視圖中添加一個路由注 (在 Northwind.Web/Scripts/app/router.js) loadView 回檔中你具有約束力網格的工具列後它已初始化並使用 MVVM 綁定已採取的地方。 這是因為您綁定您的網格,第一次工具列上沒有初始化,因為它存在的網格中。 網格第一次初始化時通過使用 MVVM,它將載入的劍道 UI 範本從工具列中。 所以它被載入到網格,你然後綁定僅向您的模型視圖工具列時您的工具列中的按鈕綁定到保存和取消您的視圖模型中的方法。 在這裡是要註冊路由定義為客戶編輯檢視的相關代碼:

router.route("/customer/index", function () {
  require(['customer-indexViewModel', 'text!/customer/index'],
    function (viewModel, view) {
      loadView(viewModel, view, function () {
        kendo.bind($("#grid").find(".k-grid-toolbar"), viewModel);
      });
    });
});

現在,您有功能齊全的客戶網格視圖。載入了 localhost:25061/主頁/Spa #/ 客戶/索引 (在您的機器的埠號將很可能會有所不同) 在一個瀏覽器,你會看到圖 12


圖 12 使用 MVVM 使用索引視圖模型的客戶網格視圖

佈線了客戶編輯檢視在這裡是將客戶編輯檢視添加到 SPA 的關鍵步驟:

  • 創建綁定到您的客戶模型通過使用 MVVM (Northwind.Web/Views/Customer/Edit.cshtml) 的客戶編輯檢視。
  • 添加客戶編輯檢視,編輯檢視模型模組 (Northwind.Web/Scripts/app/viewModels/­editViewModel.js)。
  • 添加要從 URL (Northwind.Web/Scripts/app/util.js) 獲取 Id 實用程式説明器模組。

因為你在用劍道 UI 框架,去吧,用劍道 UI 樣式的樣式您編輯的視圖。你可以瞭解更多有關,在 bit.ly/1f3zWuC圖 13 顯示的編輯檢視標記與使用 MVVM 構件和事件綁定。

圖 13 編輯檢視標記與使用 MVVM 構件和事件綁定

<div class="demo-section">
  <div class="k-block" style="padding: 20px">
    <div class="k-block k-info-colored">
      <strong>Note: </strong>Please fill out all of the fields in this form.
</div>
    <div>
      <dl>
        <dt>
          <label for="companyName">Company Name:</label>
        </dt>
        <dd>
          <input id="companyName" type="text"
            data-bind="value: Customer.CompanyName" class="k-textbox" />
        </dd>
        <dt>
          <label for="contactName">Contact:</label>
        </dt>
        <dd>
          <input id="contactName" type="text"
            data-bind="value: Customer.ContactName" class="k-textbox" />
        </dd>
        <dt>
          <label for="title">Title:</label>
        </dt>
        <dd>
          <input id="title" type="text"
            data-bind="value: Customer.ContactTitle" class="k-textbox" />
        </dd>
        <dt>
          <label for="address">Address:</label>
        </dt>
        <dd>
          <input id="address" type="text"
            data-bind="value: Customer.Address" class="k-textbox" />
        </dd>
        <dt>
          <label for="city">City:</label>
        </dt>
        <dd>
          <input id="city" type="text"
            data-bind="value: Customer.City" class="k-textbox" />
        </dd>
        <dt>
          <label for="zip">Zip:</label>
        </dt>
        <dd>
          <input id="zip" type="text"
            data-bind="value: Customer.PostalCode" class="k-textbox" />
        </dd>
        <dt>
          <label for="country">Country:</label>
        </dt>
        <dd>
          <input id="country" type="text"
          data-bind="value: Customer.Country" class="k-textbox" />
        </dd>
        <dt>
          <label for="phone">Phone:</label>
        </dt>
        <dd>
          <input id="phone" type="text"
            data-bind="value: Customer.Phone" class="k-textbox" />
        </dd>
        <dt>
          <label for="fax">Fax:</label>
        </dt>
        <dd>
          <input id="fax" type="text"
            data-bind="value: Customer.Fax" class="k-textbox" />
        </dd>
      </dl>
      <button data-role="button"
        data-bind="click: saveCustomer"
        data-sprite-css-class="k-icon k-i-tick">Save</button>
      <button data-role="button" data-bind="click: cancel">Cancel</button>
      <style scoped>
        dd
        {
          margin: 0px 0px 20px 0px;
          width: 100%;
        }
        label
        {
          font-size: small;
          font-weight: normal;
        }
        .k-textbox
        {
          width: 100%;
        }
        .k-info-colored
        {
          padding: 10px;
          margin: 10px;
        }
      </style>
    </div>
  </div>
</div>

創建一個實用程式,從 URL 獲取客戶的 ID 因為您正在創建簡潔模組與清潔邊界創建漂亮的分割線的問題,我將演示如何創建您的實用程式傭工的所有將駐留 Util 模組。 如中所示,就會入手一個公用程式方法,可以檢索 URL 中的客戶 ID 為客戶資料來源 (Northwind.Web/Scripts/app/datasources/customerDatasource.js) 圖 14

圖 14 公用程式模組

define([],
  function () {
    var util;
    util = {
      getId:
      function () {
        var array = window.location.href.split('/');
        var id = array[array.length - 1];
        return id;
      }
    };
    return util;
  });

將編輯檢視模型和 Util 模組添加到 RequireJS 配置 (Northwind.Web/Scripts/app/main.js) 中的代碼圖 15 顯示 RequireJS 配置增補為客戶編輯模組。

圖 15 RequireJS 配置增補為客戶編輯模組

require.config({
  paths: {
    // Packages
    'jquery': '/scripts/jquery-2.0.3.min',
    'kendo': '/scripts/kendo/2013.3.1119/kendo.web.min',
    'text': '/scripts/text',
    'router': '/scripts/app/router',
    // Models
    'customerModel': '/scripts/app/models/customerModel',
    // View models
    'customer-indexViewModel': '/scripts/app/viewmodels/customer/indexViewModel',
    'customer-editViewModel': '/scripts/app/viewmodels/customer/editViewModel',
    // Data sources
    'customerDatasource': '/scripts/app/datasources/customerDatasource',
    // Utils
    'util': '/scripts/util'
    },
  shim : {
    'kendo' : ['jquery']
  },
  priority: ['text', 'router', 'app'],
  jquery: '2.0.3',
  waitSeconds: 30
  });
require([
  'app'
], function (app) {
  app.initialize();
});

添加客戶編輯檢視模型 (Northwind.Web/Scripts/app/viewModels/editViewModel.js) 中的代碼圖 16 演示如何添加客戶編輯檢視模型。

圖 16 客戶的客戶視圖編輯檢視模型模組

define(['customerDatasource', 'customerModel', 'util'],
  function (customerDatasource, customerModel, util) {
    var editViewModel = new kendo.data.ObservableObject({
      loadData: function () {
        var viewModel = new kendo.data.ObservableObject({
          saveCustomer: function (s) {
            customerDatasource.sync();
            customerDatasource.filter({});
            router.
navigate('/customer/index');
          },
          cancel: function (s) {
            customerDatasource.filter({});
            router.
navigate('/customer/index');
          }
        });
        customerDatasource.filter({
          field: "CustomerID",
          operator: "equals",
          value: util.getId()
        });
        customerDatasource.fetch(function () {
          console.log('editViewModel fetching');
          if (customerDatasource.view().length > 0) {
            viewModel.set("Customer", customerDatasource.at(0));
          } else
            viewModel.set("Customer", new customerModel());
        });
        return viewModel;
      },
    });
    return editViewModel;
  });

我將簡要地描述各種元件中的代碼的圖 16

  • saveCustomer:此方法是負責在客戶上保存任何更改。它還重置資料來源的篩選器,因此網格將水化與所有客戶。
  • 取消:此方法會將導航回客戶網格視圖 SPA。此外重置資料來源的篩選器,以便在網格將水化與所有客戶。
  • 篩選器:這將調用某一特定客戶的 ID 是在 URL 中的資料來源的篩選方法和查詢。
  • 提取:這在設置篩選器後調用的資料來源提取方法。在回檔在提取的過程中,您設置您的視圖模型的客戶屬性與從您的資料來源提取,將用於綁定到您的客戶編輯檢視返回的客戶。

RequireJS 載入模組時, 的"定義"方法體中的代碼將只獲取調用一次 — — 這是 RequireJS 載入模組時 — — 所以在您編輯檢視模型中公開 (loadData) 的一種方法,所以你有一個機制來載入資料後編輯檢視模型模組已經載入 (在 Northwind.Web/ 看到這­Scripts/app/router.js)。

將路由添加為新客戶編輯檢視 (Northwind.Web/Scripts/app/router.js) 在這裡是用來添加路由器相關代碼:

router.route("/customer/edit/:id",
        function () {
    require(['customer-editViewModel',
          'text!/customer/edit'],
      function (viewModel, view) {
      loadView(viewModel.loadData(), view);
    });
  });

請注意當客戶編輯檢視模型從 RequireJS 請求時,你就能夠通過調用 loadData 方法從視圖模型檢索客戶。載入這種方式,你就能夠載入正確的客戶資料的基礎是在 URL 中每一次的客戶編輯檢視的 ID。一條路線不一定要只是硬式編碼字串。它還可以包含參數,例如後, 端伺服器的路由器 (Ruby on Rails,ASP.NETMVC,Django 等等)。要這樣做,你的名字用冒號之前你想要的變數名稱的路由段。

現在負載客戶編輯檢視在瀏覽器中的可以 (localhost:25061/主頁/Spa #/ 客戶/編輯/ANATR) 和看到所示的螢幕圖 17


圖 17 客戶編輯檢視

請注意:雖然刪除 (銷毀) 上客戶網格視圖功能具有有線向上,按一下工具列中的"刪除"按鈕時 (見圖 18),你會看到一個異常,如中所示 圖 19


圖 18 客戶網格視圖


圖 19 時刪去客戶 id 外鍵參照完整性由於客戶的預期的異常

此異常是由設計,因為大多數的客戶 Id,所以其他的表,例如,訂單、 發票中的外鍵。你將會有到電線,再將刪除所有記錄客戶 ID 在哪裡的外鍵的所有表中的級聯都刪除。雖然您不能刪除任何東西,但我仍然想要顯示的步驟和刪除功能的代碼。

所以你有它。我已經演示了如何快速並很容易將外框ASP.NETWeb 應用程式轉換成一個使用 RequireJS 和劍道 UI 的水療中心。然後展示了類似的 CRUD 功能添加到水療中心是如何容易。

你可以看到在該專案的即時演示 bit.ly/1bkMAlK 你可以在看到 CodePlex 專案工地 (和可下載代碼) easyspa.codeplex.com

編碼愉快 !

Long Le 是主要的.NET 應用程式開發建築師在世邦魏理仕公司。 和 Telerik/劍道 UI 最有價值球員。他花很多時間去發展框架和應用程式塊、 為最佳做法和模式提供指導和規範企業技術堆疊。他已與 Microsoft 技術工作了 10 年以上。在業餘時間,他喜歡寫博客 (blog.longle.net) 和玩召喚。你可以到達並跟隨他在 Twitter 上 twitter.com/LeLong37

衷心感谢以下技术专家对本文的审阅:Derick 貝利 (Telerik) 和麥克華士信 (Microsoft)