本文章是由機器翻譯。

.NET RIA 服務

建立 A 資料導向費用使用 Silverlight 3 的應用程式

Jonathan Carter

可從 MSDN 程式庫 的程式碼下載
瀏覽線上的程式碼

本文根據搶鮮版的.NET RIA 服務。所有的資訊有變更。

本文將告訴您:

  • .NET RIA 服務使用者入門
  • 資料服務 」 和 「 網域作業
  • 程式碼投影
  • 有彈性的資料控制項
本文將使用下列技術:
Silverlight 3,.NET RIA 服務,WPF

內容

使用者入門
資料服務的程式庫
網域操作
程式碼投影
資料控制項
ObjectDataSource
DataPager
DataForm
中繼資料
驗證
共用程式碼
設定自動換行

在軟體開發, 有是每一個都有它自己的目的和需求,優點和缺點的應用程式的許多不同樣式。請選擇一個開發平台或 Framework 時, 您的決策程序的一部分最有可能會依賴是否.Framework 可以輕鬆地啟用您要尋找以建置的應用程式的類型。沒有開發人員想要花時間撰寫配管或基礎結構程式碼,並沒有客戶想要購買該類型的工作進行]。能夠主要是著重在商業需求很重要,所以有一個開發平台,更讓的焦點,並增加生產力是絕對必須。

Silverlight 會是用來建立吸引人的 Web 應用程式一項很棒的技術。雖然 Silverlight 2.0 會包含 Windows Presentation Foundation (WPF) 的子集,未繼承在相當的時間在 WPF 中做它更容易建立資料驅動的應用程式的功能。這導致許多開發人員將最後設定上使用 Silverlight,因為它會需要太多的工作實作更複雜的 Web 解決方案的資料中心基礎結構。隨著 Silverlight 3 發行,新控制項和功能會被採用,特別是讓更容易開發資料導向的應用程式。這包括新的資料控制項、 巡覽、 驗證和 Windows 內嵌的對話方塊。

雖然這些用戶端的增強功能提供自己的 Silverlight 大量值則是一個多層的環境,而且因此需要知道如何處理用戶端與伺服器通訊。如果要解決這個問題,.NET RIA 服務 (代號為"Alexandria 」) 提供一組伺服器元件] 以及 [ASP.NET 延伸簡化 N 層 (N-Tier) 開發程序,使得您的應用程式幾乎為容易開發,如果它們已執行單一的層。此外,提供服務,例如驗證、 角色和設定檔管理。用戶端和伺服器的增強功能 Silverlight 3] 和 [ASP.NET 以及搭配.NET RIA 服務的組合簡化開發資料導向 Web 應用程式的端對端經驗 — 也稱為完備網際網路應用程式或 RIA。

fig01.gif

[圖 1 的 預設.NET RIA 服務專案

在這的篇文章我將示範如何對 Silverlight] 3 的正常功能由.NET RIA 服務,引入增強功能給您一個豐富型環境開發資料中心的 Web 應用程式。為了最佳說明功能,Silverlight 3 和.NET RIA 服務提供,我要建置出的費用報表,追蹤會利用新的功能集的應用程式。應用程式將會允許在記錄及管理並建立其個人的費用報表的員工。一旦完成的費用報表,它可以再送出,等候資料管理員的核准。

使用者入門

一旦您已安裝.NET RIA 服務] 和 [Silverlight 3,Visual Studio 就會包含呼叫 Silverlight 資料應用程式,可讓您取得設定新專案範本] 和 [快速地執行。當建立您的解決方案時,您要顯示兩個專案: 一個 Silverlight 專案] 和 [ASP.NET 專案 (請參閱 [圖 1 )。Silverlight 專案則表示您的用戶端應用程式],而 ASP.NET 專案將會包含您的後端邏輯。

這個預設的專案結構的優點是什麼?到為提供的 Silverlight 專案會,它等於您想得到如果您建立規則的 Silverlight 專案。您有標準的 App.xaml 檔案] 和 [預設的網頁。有,但是,細微差異,將會協助您開發的目標這個 Silverlight 專案。

ASP.NET 專案將以及,是直接了當,但如果您查看 Default.aspx 頁面中的,您會發現它會使用新的伺服器控制項會呼叫 SilverlightApplication。

<ria:SilverlightApplication 
  ID="Xaml1" runat="server" 
  Source="~/ClientBin/ExpenseReports.xap" 
  MinimumVersion="1.0" 
  Width="100%" Height="100%" />

這個控制項是用來進行的裝載 Silverlight 應用程式更容易在 ASP.NET WebForm 應用程式中。 SilverlightApplication 控制項已經設定為目標,XAP 從 Silverlight 的專案將建立的。

這時候您會有完整的功能和裝載 Silverlight 應用程式。 現在您只需要開始加入自訂的商務邏輯和 UI。

讓我們假設您已經了資料庫在位置此的應用程式的 ADO.NET 的實體資料模型中加入伺服器專案下一件事是。 我會使用 Entity Framework 做為這的篇文章中的 [(O / RM)] 的 [物件關聯] 對應,但您可能會也使用 LINQ to SQL、 NHibernate、 傳統的 ADO.NET 或任何其他的資料存取方法]。

資料模型是非常簡單,包含只有三個項目: ExpenseReport,ExpenseReportDetail,和員工 (請參閱 [圖 2 )。 如需詳細資訊, ADO.NET Entity Framework MSDN。

fig02.gif

[圖 2 資料模式

與資料模型就位並在進行 O / RM 選取,您現在可以開始實作後端) 邏輯。 因為這個專案會採用 Silverlight 與用戶端和 ASP.NET 為主機,您必須在這兩層之間進行通訊的方法所決定。 您可以使用其中一個,目前可用的通訊架構,例如,Windows Communication Foundation (WCF) 或 ADO.NET 資料服務,根據需求而定。

資料服務的程式庫

.NET RIA 服務會介紹建置資料導向 RIA 簡單的伺服器元件的程式庫。 程式庫不依賴任何特定的 UI Framework,而雖然本篇文章著重於由 Silverlight 的消耗量,則是只其中一個其可能的用戶端的選項。 在未來版本,.NET RIA 服務也將使用 ADO.NET 資料服務。

.NET RIA 服務主要是隨著新的類別,稱為 DomainService,做為一個伺服器端點的商務邏輯和資料模型互動。 建立一個很簡單,以利用商業邏輯類別由.NET RIA 服務,在 Visual Studio 中所安裝的範本 」 中。

在 DomainService 可以位於兩個表單: 資料 model–specific 或泛型。 資料 model–specific 實作會有效地包裝資料模型,可讓您撰寫的商務邏輯和資料存取程式碼組合的選項。 這讓更方便以取得設定,且快速地在其中您已經有資料模型,您要使用的案例中執行。

都有是實兩個資料 model–specific DomainService 作隨附.NET RIA 服務: ADO.NET Entity Framework 」 和 「 SQL 的 LINQ。 如果您的應用程式會使用其中的然後再建立一個 DomainService 時,您可以在精靈選取適當的選項。 如果您使用其他類型的資料模型] 或 [O / RM,您可以建立自己的一個 DomainService 以及特定的實作。

本文,因為我已經有的實體資料模型在位置,我將繼續並建立實體 Framework–specific DomainService。 我收到新類別,繼承自 LinqToEntitiesDomainService <t>:

[EnableClientAccess]
public class ExpenseService : 
  LinqToEntitiesDomainService<ObjectContext> {

  //public IEnumerable<Employee> GetEmployees()
  //{
  //    return this.Context.Employee;
  //}
}

泛用參數,在這種情況下表示 ObjectContext 執行個體,表示在連接至實體資料模型的型別。 在第一個步驟是 heed TODO 註解的建議,並取代在這個案例的 ExpenseReportContext 的實際 ObjectContext 的型別參數預留位置。

除了繼承 DomainService (或在 CSimpleSoapAppService) 網域服務可以擁有附加的 EnableClientAccessAttribute。 這個屬性真的表示您的網域服務的類別也可讓您指定是否它應該公開公開。 藉由公開公開,我是指可存取您的用戶端應用程式。 這會讓您選擇以判斷是否在的伺服器上僅需要一些邏輯,或如果它也應該在用戶端上使用。

網域操作

網域服務在除非您將某些功能新增至網域作業的形式不自己很有用。 在 [網域] 作業表示您的網域服務的端點,和可以執行建立、 讀取、 更新,和刪除 (CRUD) 作業,對您的資料模型、 您的任意的商務邏輯或兩者。 每個網域的作業必須對應,包括查詢、 插入、 更新、 刪除、 服務的作業及自訂為特定的作業型別。 作業的型別對應可能會發生依慣例或組態。

根據您的網域作業要執行的作業類型,它必須遵循特定的簽名碼。 此外,某些作業必須遵循特定的命名慣例,或是有屬性,判斷何種作業,它是型別。 執行個體,如果它是 「 查詢 」 作業的則其傳回型別必須是 IEnumerable <T> 或 IQueryable <T> 其中 T 是實體型別就會使用。 它可以接受任何數目的參數可以做為篩選器,但都需要]。

建立網域作業中擷取所有的支出報表可能如下所示:

public IEnumerable<ExpenseReport> 
  GetExpenseReports() {

  return Context.ExpenseReports;
}

ExpenseReport 是基礎的資料模型中的實體,因此,有效的傳回型別。 DomainService 類別會包含一個稱為內容,提供存取您資料的模型 (型別您提供泛用參數),可在這種情況下的所有的支出報表清單中讓您查詢的執行個體的屬性。 這項作業會對應至型別上,依慣例。

建立資料的方法,擷取特定的費用報表可能如下所示:

[Query(IsComposable = false)]
public IEnumerable<ExpenseReport> 
  GetExpenseReport(int id) {

  var expenseReport = 
    from rep in Context.ExpenseReports
    where rep.Id == id
    select rep;

  return expenseReport;
}

請注意此資料的方法參數來擷取特定的費用報表的識別碼。 因為您需要存取基礎的 ObjectContext,您也可以撰寫使用 LINQ 查詢。 這個方法會使用它也可讓您指定無法 conventionally 達成的其他屬性,QueryAttribute 的組態對應。 我會在 [QueryAttribute,IsComposable 屬性用途在本文稍後觸控。

許多查詢方法,視需要可以包含一個 DomainService。 除了擷取資料,您可以建立的保存資料回資料模型的作業。 費用報表實作基本的持續性的作業 (插入 / 更新 / 刪除) 可能如下所示:

public void InsertExpenseReport(
  ExpenseReport expenseReport) {
  Context.AddToExpenseReports(expenseReport);
}

public void UpdateExpenseReport(
  ExpenseReport current, ExpenseReport original) {
  Context.AttachAsModified(current, original);
}

public void DeleteExpenseReport(
  ExpenseReport expenseReport) {
  Context.DeleteObject(expenseReport);
}

您可在許多相同的方式定義費用報表詳細資料在永續性作業。 您可以只使用單一插入、 更新,及刪除每個實體的型別 (在這個案例中為 ExpenseReport) 的方法,因為,the DomainService 時要求在將變更存回資料模型,DomainService,需要知道要呼叫的方法。

請注意有關這些作業是其簽名碼。 建立插入或刪除方法時, 它就必須接受單一參數符合方法負責插入或刪除實體型別。 當您建立的更新方法時,它就必須接受兩個參數: 修改 (或) 目前的實體執行個體和原始的實體執行個體。 在方法簽名碼,搭配方法名稱都是表示到哪一個方法負責的實體類型的作業,DomainService。

命名慣例可用於定義永續性的作業為您的作業型別的方法名稱的前置詞。 執行個體,因為方法呼叫 DeleteExpenseReport,刪除前置字元表示,是依慣例在刪除作業。 簽名碼,然後定義哪些實體型別,它會與 (ExpenseReport) 產生關聯。 如您所預期傳統的方法名稱前置詞是更新的更新作業,並插入作業是 [插入]。 這就是為何我沒有執行任何額外的設定,這些工作的作業。

如果作業不遵循,預期的命名慣例,或您需要指定您的作業 (像我使用 GetExpenseReport 方法) 的其他中繼資料,然後您可以套用組態屬性,例如 QueryAttribute 」、 「 InsertAttribute 」、 「 DeleteAttribute 和 「 UpdateAttribute,我一樣使用 GetExpenseReport 方法中。

如果要定義的商務邏輯,不一定要繫結至 「 CRUD 」 作業,但在關聯的實體類型,您可以建立一個服務的作業。 在這種情況下,我要核准及拒絕支出報告的作業。 這只是表示修改費用報表的狀態值 (請參閱 [圖 3 )。 服務作業的簽名碼必須接受實體型別和它關聯並必須傳回 void 的執行個體。 請注意有沒有慣例定義服務作業,因此您必須套用 ServiceOperationAttribute,設定適當的網域的任何作業。

[圖 3 服務作業

[ServiceOperation]
public void ApproveExpenseReport(
  ExpenseReport expenseReport) {

  if (expenseReport.Status == 1) {
    if (expenseReport.EntityState == 
      System.Data.EntityState.Detached) {
      Context.Attach(expenseReport);
    }
    expenseReport.Status = 2;
  }
}

[ServiceOperation]
public void RejectExpenseReport(ExpenseReport er) {
  if (er.Status == 1) {
    if (er.EntityState == 
      System.Data.EntityState.Detached) {
       Context.Attach(er);
    }
    er.Status = 0;
  }
}

現在,你網域服務和作業建立,如何執行您移有關從 ASP.NET 伺服器主機到 Silverlight 的用戶端應用程式服務與互動? 如果您已使用 WCF] 或 [ADO.NET 資料服務,您會建立參考,服務會產生 Proxy 所指向的 Silverlight 專案中。 .NET RIA 服務會提供稍微更豐富經驗。

程式碼投影

當您建立.NET RIA 服務解決方案時,Silverlight 專案檔就會有一些特殊 MSBuild 工作加入至處理用戶端投射特定伺服器元件。 當您在已套用的 EnableClientAccessAttribute ASP.NET 專案中建立網域服務時, MSBuild 工作將專案的網域服務,Silverlight 應用程式。 (如果您沒有建立您的方案使用新的 Silverlight 資料應用程式專案範本,您可以手動方式連結一個 Silverlight 專案] 和 [ASP.NET 專案,Visual Studio,來達到相同效果)。

如果您查看 Silverlight 專案中 main.xaml 檔案的程式碼後置,您會發現同時 ExpenseContext 和 ExpenseReport 型別。 當資料提供者投射到 Silverlight 的用戶端應用程式時,它不再使用 DomainService (或子型別) 而 DomainContext 但。 事實上,如果與 Word 服務,為您的網域服務,它將會取代內容時 (這是為 ExpenseService 類別會反映在 Silverlight 專案費用內容為什麼) 的投影。 DomainContext 類別會做為一個 DomainService 用戶端 Proxy,並包含必要的通訊要求,在這兩層之間的邏輯。 它代表的工作單位,並可以建立一系列的變更集對它目前正在追蹤任何實體執行個體。

某些方法 (會被視為慣例或組態的網域操作的公用方法) 連同其父代的預估此外,網域服務。 只有三個預估的六個的資料方法型別,: 自訂,服務,及查詢。 如果查詢方法的名稱,以取得有前置,投影時取得會被取代載入。 例如,因為我定義一個名稱 GetExpenseReports 查詢方法,它將會出現在用戶端上為 LoadExpenseReports。 兩個服務的作業以及預估,並會在 DomainContext 上,為執行個體方法反映。

最後,將也投射會從網域作業傳回的任何實體型別。 <expensereport>在我的範例因為 GetExpense-報告方法的傳回型別 IEnumerable < ExpenseReport > ExpenseReport 的實體類別將被投射 Silverlight 用戶端。 預測的實體類別會繼承自特殊的類別,稱為 Entity,提供行為,例如變更追蹤、 驗證檢查和 WPF / SL-相容 editability。 API 觀點的您的用戶端的實體類別會看起來實體類似,只是在的伺服器上,但是將會包含所需的互動與 Silverlight 資料控制項的其他功能。

有許多的更多周圍程式碼投影行為與此處所討論的詳細資料。 本文不會在許多其他的案例可能包括自訂邏輯,決定特定型別的程式碼如何形之前,先將它往投影到用戶端應用程式的接觸的。

我使用詞彙的程式碼投影,因為我認為它會適當地描述所進行。 ExpenseService 類別無法直接被從複製一個專案到另一 (沒有實際的例外狀況這我稍後會討論)。 它會被檢查,形狀,和預測到用戶端應用程式為一個容易使用的 Proxy。 因此,您可以利用型別從用戶端層,如同它是本機的物件。

位置隱藏預計的網域服務? Silverlight 專案從其建立的狀態會不變的。 如果您開啟顯示 Silverlight 專案的所有檔案] 選項時,將就會看到罪犯 (請參閱 [圖 4 )。 會建立稱為的 Generated_Code,其中包含程式碼已經被投射從協力廠商伺服器專案的所有資料夾。 目前沒有只有一個檔案有,ExpenseReportsServer.g.cs (g) 表示,為產生) 的包含整個 ExpenseReportsServer 專案的程式碼及是 ExpenseContext 類別的 [首頁。

fig04.gif

[圖 4 ]: Silverlight 專案所產生的程式碼

如果您會建立新的資料提供者,或修改現有,變更將會無訊息地更新 Silverlight 專案,保持在用戶端和伺服器的持續同步內。 在支援的應用程式的用戶端的唯一目的,建立服務的案例需要不斷地重新整理服務 Proxy,在開發期間,可以是在痛苦。 除了期間投影,reshaping 這個細微行為結果是很有用的功能。

資料控制項

因此我了資料庫、 資料模型、 服務和用戶端 Proxy 在位置。 現在我需要建立出顯示和編輯費用報告資料,在 Silverlight 用戶端 UI。 處理資料導向的應用程式時有通常是兩種的資料的呈現方式: 表格式和] 表單的基礎。 當處理資料導向 RIA 表格式和表單架構資料需要以,可讓使用者經驗,高度資訊和生產力的方式呈現。

Silverlight 2 沒有現成的有很強式支援表格式資料的簡報。 甚至 ListView 控制項 (它會提供基本的格線的簡報,在 WPF 中) 是存在於它讓有點難以建置企業軟體的 Silverlight。 Silverlight 稍後會收到一定已協助 T DataGrid 控制項,但許多必要的功能已還是遺漏了。 內建 (Intrinsic) 控制項是可用的例如 TextBox、 下拉式方塊、 按鈕、 ListBox 和它進行開發的表單可能的 RadioButton,但是有沒有其他行為,例如資料驗證和錯誤報告所需的強大的支援。

Silverlight 3 引進了一組新的控制項,特別是針對方便建立的資料中心 RIA。 這些控制項包括 DataGrid、 DataForm、 DataPager、 FieldLabel、 DescriptionViewer、 ErrorSummary 和 ChildWindow。 我利用 DataGrid、 DataForm 和 DataPager 啟用資料簡報 Tabular] 和 [我的範例應用程式的表單架構樣式。 FieldLabel DescriptionViewer,ErrorSummary 提供動態 UI、 資料驗證,和回應的資料項目的開發所需的錯誤報告。 最後,ChildWindow 可讓 RTF 強制回應 (Modal) 對話方塊。

在 DataGrid 控制項隨附 Silverlight 3 是強大大小寫。 除了其他的功用外,其中包括 reorderable 和可調整資料行、 資料列的群組、 內嵌編輯,和驗證。 它可讓您定義有兩種方格中顯示資料行: 產生和明確。

DataGrid 具有其 AutoGenerateColumns 屬性集 」 true 會以,自動建立它所繫結至型別上的每個公用屬性資料行,例外狀況的如果屬性附加到其在 BindableAttribute,指定它不是可繫結,然後 DataGrid 無法為它建立一個資料行。 這是一個範例如何在新的資料控制項利用實體中繼資料。

當您明確地定義資料行中的 DataGrid 時,您的範圍設定只是您要顯示的資料行顯示的資料。 這可讓您控制哪些資料行型別使用,以及頁首文字和許多其他資料行屬性。 明確地定義其資料行顯示費用報告資料的 DataGrid 可能如下 [圖 5 中。

費用報表] 的 [圖 5 DataGrid

<dataGrid:DataGrid
  x:Name="ExpenseReportDataGrid"
  AutoGenerateColumns="False">
  <dataGrid:DataGrid.Columns>
    <dataGrid:DataGridTextColumn 
      Binding="{Binding Company}" 
      Header="Company" />
    <dataGrid:DataGridTextColumn 
      Binding="{Binding Department}" 
      Header="Department" />
    <dataGrid:DataGridTextColumn 
      Binding="{Binding Description}" 
      Header="Description" />
    <dataGrid:DataGridCheckBoxColumn 
      Binding="{Binding Status}" 
      Header="Approved" />
  </dataGrid:DataGrid.Columns>
</dataGrid:DataGrid>

資料行繫結中所指定的屬性會指向 ExpenseReport 實體上的屬性。 請記住類別投射到 Silverlight 應用程式使其能在用戶端。 DataGridTextColumn 類別為唯讀模式中的文字和文字方塊,在編輯模式下,將會顯示資料。 在 DataGridCheckBoxColumn 將會顯示為在所有模式中核取方塊的欄位,並符合三種狀態中。

若要填入 DataGrid 您只要將其 ItemSource 屬性設定為任何的 IEnumerable 物件。 請記住當我定義費用的服務和 GetExpenseReports 資料方法,其傳回型別會是 IEnumerable <expensereport>。 現在我只需要知道如何使用用戶端 Proxy 產生的資料提供者。

當 ExpenseService 類別已投射到用戶端應用程式時,其 GetExpenseReports 方法已 (之後被重新命名為 LoadExpenseReports) 以及預估。 這表示您應該可以只建立 ExpenseService 的執行個體,並呼叫其 LoadExpenseReports 方法。 時,才能正確方法,它不會產生任何自己的搜尋結果。 有趣的是,LoadExpenseReports 方法不會傳回任何項目。 您要如何取得費用報告資料?

Silverlight 會需要任何封鎖的呼叫,以便在 UI 執行緒沒有鎖定以非同步方式執行。 有鑑於此,.NET RIA 服務專案 Silverlight 用戶端,您網域的服務時它 refactors 其查詢作業的所有,讓它們不再傳回任何項目。 這說明為什麼.NET RIA 服務將會重新命名會加上載入而取得 (或擷取、 尋找、 查詢、 擷取或選取),更適當地反映其行為,因為您查詢方法。

而非使用一個回呼方法,.NET RIA 服務所產生類別會使用的事件模型的非同步呼叫完成後,請通知您。 因此,來回應查詢作業的載入,您只要訂閱 DomainContext 的載入事件,一旦完成的任何查詢作業就會觸發的。 因為事件處理常式會在 UI 執行緒上呼叫的您可以執行任何的資料繫結中。

[圖 6 費用報表資料載入

public partial class Main : Page {
  ExpenseContext _dataContext;

  public Main() {
    InitializeComponent();

    this.Loaded += Main_Loaded;

    _dataContext = new ExpenseContext();
    _dataContext.Loaded += dataContext_Loaded;
  }

  void dataContext_Loaded(object sender, LoadedDataEventArgs e) {
    ExpenseReportDataGrid.ItemsSource = e.LoadedEntities;
  }

  void Main_Loaded(object sender, RoutedEventArgs e)  {
    _dataContext.LoadExpenseReports();
  }
}

fig07.gif

[圖 7 費用報表方格 UI

一旦觸發載入的事件處理常式有擷取您要求的資料兩種方法: 透過 LoadedDataEventArgs.LoadedEntities 屬性,或透過其中一個強型別的實體屬性,在您的網域內容 (例如 ExpenseContext)。 存取資料,透過事件引數是慣用的方法,因為這會確保您取得要在的資料。 每次呼叫在查詢作業,傳回的實體執行個體將加入至的網域內容因此只要您存取其內容,您會取得每個查詢,不只是一個您最近執行的累積。

擷取所有的支出報表的填入傳回之資料的 DataGrid 邏輯的實作可能會如下 [圖 6 。 這時候我們的資料導向 RIA 看起來像 [圖 7 中。

除了能夠載入資料,DomainContext 類別 (和您產生的子型別) 包含了管理追蹤變更 」 和 「 資料永續性的方法。 將追蹤每個您透過一個 DomainContext 對已擷取 (或加入或刪除) 的實體的變更。 要儲存變更時您可以直接呼叫 SubmitChanges 方法:

private void SaveChangesButton_Click(
  object sender, RoutedEventArgs e) {
  if (_dataContext.HasChanges) {
    _dataContext.SubmitChanges();
  }
}

因為 DataGrid 可讓內嵌編輯預設的情況下,您可以修改任何的費用報告記錄並按一下 [儲存變更] 按鈕,將它們保存至伺服器。 在呼叫 SubmitChanges 方法時,DomainContext 組合設定的追蹤項目的所有變更並將它傳送至對應的 DomainService。 在 DomainService decomposes 變更集然後呼叫已插入、 更新,或刪除的每個實體的個別的網域作業。

編輯 DataGrid 控制項內的資料時它會提供驗證和自動報告的錯誤。 如果您輸入無效資料時,您會收到以視覺化方式通知的錯誤的說明 (請參閱 [圖 8 )。 這項功能就沒有任何組態或工作在您的組件上。 您會發現本文稍後,您也可以將挑選及確保 DataGrid 的您的資料模型上定義自訂的驗證規則。

fig08.gif

[圖 8 DataGrid 驗證

費用報表此檢視是正常的但會是許多更有用,以查看費用 (依狀態。 這樣我無法立即知道的報表是擱置的管理員的核准。 幸好,這可以達成輕鬆地在 Silverlight 3 將這個程式碼附加現有的 DataGrid 定義:

<dataGrid:DataGrid.GroupDescriptions>
  <dataGrid:PropertyGroupDescription  
    PropertyName="Status" />
</dataGrid:DataGrid.GroupDescriptions>

結果看起來像 [圖 9 .

fig09.gif

[圖 9 DataGrid 的群組

ObjectDataSource

雖然有些開發人員會喜歡命令式資料繫結到目前為止所使用的方法,其他可能會希望能夠執行資料繫結完全宣告的方式非常類似方式可能使用 ObjectDataProvider 在 WPF 中。 此,Silverlight 3 會介紹 ObjectDataSource 控制項。

ObjectDataSource 將是您,隱藏式控制項,知道如何使用特別 DomainContext 型別。 可以想但表示提供的所有功能,先前的命令式方法沒有完全的宣告式 (加號)。 您只要告訴它您正在使用哪一種 DomainContext 類型以及其中一個您要呼叫其查詢作業。 ObjectDataSource 會處理其餘部分。

您無法在所有的程式碼移除前一節,並以 ObjectDataSource,取代,並它將會自動呼叫指定的載入方法的:

<ria:ObjectDataSource
  x:Name="ExpenseReportsObjectDataSource"
  DataContextType="ExpenseReports.ExpenseContext"
  LoadMethodName="LoadExpenseReports"
  PageSize="20">
  <ria:ObjectDataSource.Filter>
    <data:FilterDescriptor Member="Department" 
      Operator="IsEqualTo" Value="IT" />
  </ria:ObjectDataSource.Filter>
  <ria:ObjectDataSource.Sort>
    <data:SortDescriptor Member="Status" 
      Direction="Descending" />
  </ria:ObjectDataSource.Sort>
</ria:ObjectDataSource>

使用 ObjectDataSource 控制項不只是提供資料繫結的宣告式方法,它也會使查詢 composable。 您可以加入排序、 群組和篩選條件運算式的 ObjectDataSource,以及將套用至其查詢作業呼叫的頁面大小。 最精采的部分是的 ObjectDataSource 會修改要求對網域服務,讓指定的排序或篩選會套用在伺服器端,表示會透過網路傳遞任何不必要的資料。

請記得,DomainOperationAttribute,IsComposable 屬性嗎? 這是決定網域作業是否允許其他查詢參數傳送給它的,發出其傳回的資料 composable。 我的 GetExpenseReports 方法沒有新增任何排序或篩選條件程式碼的但是因為的 composability,DomainService 的 ObjectDataSource 會知道如何進行,撰寫查詢,我也可以自動取得該功能。

ObjectDataSource 會會包裝函實際式 DomainContext 執行個體,並因此受益相同的行為變更的追蹤。 它包含相同的負載和 SubmitChanges DataContext 不會,可讓您如同在 DomainContext 以程式設計方式控制的方法。

DataPager

因為在方格中目前顯示的資料量是有點不易,它就可能合理它網頁進行簡報。 雖然 DataGrid 控制項本身不包含分頁行為,Silverlight 3 引進了新 DataPager 控制項完美地運作,與其他資料控制項,以輕鬆地提供分頁的功能,與它們。

DataPager 控制項只會提供必要的分頁 UI 透過提供的資料來源。 如果您繫結至相同的資料來源 (例如 DataGrid) 的另一個資料控制項的一個 DataPager,使用 [DataPager 資料分頁也將頁面其他繫結控制項中所顯示的資料。 程式碼加入的費用報表清單中的一個 DataPager 可能如下所示:

<data:DataPager
  Source="{Binding Mode=TwoWay, Source={StaticResource ExpenseReportDataSource}, Path=Data}"/>

fig10.gif

[圖 10 DataPager 放在方 A DataGrid: 後面

請注意我只需要定義控制項,並在繫結至正確的來源控制項將會處理其餘部分 (請參閱 [圖 10 ).

在 DataPager 會有許多的模式您可以從選取不同如何它向可用分頁使用者。 此外,您可以完全 re-skin DataPager,尋找但您想要同時仍維持其現有的功能。

雖然 DataPager 與 DataGrid 會提供一個很棒的內嵌編輯經驗,如果您想要在表單架構的版面配置中顯示資料? 建立或修改費用報表,您要提供使用者與使用,而不必依賴方格非直覺式表單。 ,您可以採用新的 DataForm 控制項。

DataForm

DataForm 控制項可讓您定義一組欄位,會顯示在表單架構的版面配置,並且可以繫結至是一個單一的實體執行個體或集合。 它允許唯讀使用您的資料,、 插入,並編輯模式,能夠自訂的外觀。 您可以選擇性地顯示切換模式及,繫結至集合時,DataForm 也可以顯示巡覽的一個頁面巡覽控制項。 就像在的 DataGrid DataForm 也有各種不同形式: 產生、 明確,和範本。

產生的模式運作,就像 DataGrid。 它會繫結至型別上,以建立每個公用屬性欄位和標籤組。 DataForm 會遵守,BindableAttribute,也可讓您定義在實體層級您可繫結的欄位清單。 支出報表的 [編輯] 表單的定義可能是像這樣簡單:

<dataControls:DataForm
  x:Name="ExpenseReportDataForm" Header="Expense Report"
  ItemsSource="{Binding Source={StaticResource ExpenseReportsObjectDataSource}, Path=Data}" />

利用產生的模式中,您要允許 DataForm,以便根據實體的中繼資料的所有 UI 假設。 得出的表單如 [圖 11 ] 所示。

fig11.gif

[圖 11 DataForm-衍生費用項目表單

粗體標籤的任何必要的欄位 (使用需要的屬性標記的屬性) 會顯示在顯示,指出使用者需求。 而且,至輸入控制項右邊資訊) 圖像 (Glyph) 會提供預期的輸入的滑鼠經過工具提示說明。 描述是選擇性的並是否欄位的對應屬性都具有附加一個 DescriptionAttribute,藉由檢查擷取。 這些是兩個多個的範例的新的 Silverlight 3 資料控制項如何啟用資料驅動的案例,新增至您的 UI,以回應您的資料模型中繼資料。

就像在的 DataGrid,DataForm 也會提供資料驗證和錯誤報告。 兩個控制項都有一致的外觀及提供的整體良好的使用者經驗,不論哪些資料展示您所需要的功能。

您可以使用明確表單,宣告您要的欄位顯示時的欄位,以使用,類型,並 (等等) 中顯示哪些標籤文字。 時您不希望讓 UI 建立多達 DataForm 和實體中繼資料,則此表單很有用。 明確宣告為 DataForm 可能如下 [圖 12

[圖 12 Of A DataForm 明確的建立

<dataControls:DataForm
  x:Name="ExpenseReportDataForm"
  ItemsSource="{Binding Source={StaticResource ExpenseReportsObjectDataSource}, Path=Data}"
  AutoGenerateFields="False">
  <dataControls:DataForm.Fields>
    <dataControls:DataFormTextField 
      Binding="{Binding Company}" Label="Company" />
    <dataControls:DataFormTextField 
      Binding="{Binding Department}" Label="Department" />                
    <dataControls:DataFormTextField 
      Binding="{Binding Description}" Label="Description" />
    <dataControls:DataFormCheckBoxField 
      Binding="{Binding Status}" Label="Approved" />
  </dataControls:DataForm.Fields>
</dataControls:DataForm>

除了文字的核取方塊的欄位,有欄位日期、 下拉式方塊、 範本、 分隔符號、 標頭,和欄位群組。 使用這些,您可以明確地定義,您要顯示,並提供基本的指令,DataForm 顯示它們的欄位。 即使有這樣的彈性,您是仍然限制在上方上下表單,其中的每個欄位是一個傳統標籤] 和 [輸入控制項組。 而在 DataFormTemplateField 可以讓您定義的所有模式 (顯示和編輯) 範本,它受限於使用欄位層級。 如果您想要範本整份表單?

完全掌控您的 UI 是需要 (或想要) 時, 則在 DataForm 可讓您為每個其模式,請 (顯示、 插入和編輯) 中定義的自訂資料的範本。 與這項功能,您可以預設由上到下表單樣式出的中斷,以及建立任何的外觀會對您的情況合理。

特定的行為是所有三個的表單,DataForm,例如巡覽、 驗證,和錯誤報告的全域的。 當您選擇重新定義資料範本,但您遺失,自動欄位標籤及說明檢視器 」 的使用您的模型中繼資料。 開發資料導向的應用程式,將會 shame,遺失這個有用的行為,因為您需要自訂您的版面配置。 幸運的是,在控制項,在 dataform 在內部使用,] 和 [提供這種行為也是可用以手動方式。

中繼資料

當您允許 DataForm,為您產生的欄位清單時, 它會自動將使用兩個控制項來提供標籤和描述的行為: FieldLabel 和 DescriptionViewer。 這些控制項的都容易使用和可以運用在任何資料繫結案例中,包括自訂 DataForm 範本。

當您想要顯示在標籤控制項從其相關聯的繫結屬性的中繼資料所決定,FieldLabel 就很有用的。 在標籤所使用的文字被衍生自 [DisplayAttribute 附加至它繫結的屬性的名稱屬性中。 此外,如果屬性為必要 (藉由在出現 RequiredAttribute 標示為 true,附加到其所表示),欄位的標籤文字會以粗體。

除了能夠指定自訂的名稱與在 DisplayAttribute,您可以指定屬性的描述。 如果您想顯示欄位的描述,您可以使用 DescriptionViewer 控制項,處理此為您自動。 它會顯示的資訊的圖像,提供工具提示包含的屬性與它關聯的描述。

與 FieldLabel 和 DescriptionViewer 控制項中,您可以開發利用從您的資料模型中繼資料,而不需要複寫資訊 (例如,欄位名稱和描述) 的自訂資料表單。 如果您是在應用程式使用這些控制項,變更屬性的名稱、 描述,或所需的狀態 (在模型層級),任何時間您的 UI 會自動反映因為其相依性,以資料模型變更。 這是行為的您預期開發資料導向的應用程式時的類型。

驗證

因為我們著重開發資料導向的應用程式,我們希望保持我們的商務邏輯和接近資料模型的驗證。 使用.NET RIA 服務時,您可以 Express 驗證邏輯,有兩種: 資料註釋] 和 [自訂 / 共用邏輯。

Microsoft.NET Framework 3.5 SP1 的發行版本會採用一組稱為資料註釋,用來附加資料模型中繼資料和驗證規則的屬性。 這些註釋會一開始由 ASP.NET 的動態資料和瞭解,遵守.NET RIA 服務和新的 Silverlight 3 資料控制項。 您可以使用這些 Express 這類驗證方面,字串的長度、 範圍、 資料型別,和規則運算式的條件約束:

[Bindable(true, BindingDirection.TwoWay)]
[Display(Name = "Expense Amount", 
  Description = "The amount of the incurred expense.")]
[Range(0.0, 1000000.00)]
public object Amount;

[Bindable(true, BindingDirection.TwoWay)]
[Display(Name = "Category", 
  Description = "The category of expense, i.e., mileage.")]
[StringLength(10)]
public object Category;

在.NET RIA 服務投影處理執行時,會指向傳送至用戶端的任何伺服器端資料註釋。 只要您利用泛型資料註釋,以表示您的伺服器端資料模型上的驗證規則,驗證將會透過您的 Silverlight 應用程式的執行,並注意 (DataForm、 DataGrid、 FieldLabel,等等) 的控制項的完整使用。 這可以有效地讓您用戶端和伺服器的驗證。

使用資料的註釋簡單,但是他們無法 Express 每個可能的驗證需求。 事實上,它們可以真的代表最常見的案例。 其他的情況下您可能要命令定義您的驗證。 雖然這是簡單執行,.NET RIA 服務投影程序無法只限制為您 DataContext 和實體的 Proxy 類別的建立該處理序為傳送您的自訂邏輯至用戶端。

您也可以將保留 [伺服器上的 [自訂的邏輯,並讓呼叫它從您的 Silverlight 用戶端服務,但是,也會刪除應用程式的回應,並移除資料控制項以自動判斷資料的有效性讓。 您可以複製和貼上的邏輯,以便在的用戶端和兩層,手動執行驗證,但程式碼的複寫不會是個好的方法,以及自動驗證問題仍然存在。 這是案例的擔保,使用.NET RIA 服務共用的程式碼功能。

共用程式碼

在的費用報告應用程式我需要確保兩個自訂驗證規則: 透過 $ 1,000 的任何匯出報告必須包含分層顯示其目的,描述,並沒有費用會報告可以未來的購買的欄位。 這些條件都不可以符合使用資料的註釋,但我可以輕易地表示它們命令。

.NET RIA 服務會包含稱為共用的程式碼,可讓您定義邏輯,您將會同步處理,並您用戶端應用程式中可用的伺服器專案中功能。 程式碼,規劃程序期間會被標記為共用的任何程式碼複製而非轉譯,並進行 Proxy 處理的專案之間。 若要利用這項功能的您先建立新的程式碼檔案在伺服器專案使用.shared [語言擴充功能] 的尾碼 (例如 ExpenseData.shared.cs)。 當程式碼的規劃程序執行時, 它特別會尋找使用該尾碼專案中的檔案,並處理它,共用程式碼。

沒有新的資料註釋,在.NET Framework 4.0 呼叫 CustomValidationAttribute,可讓您關聯實體或在屬性層級資料模型的自訂驗證規則。 指定 [我的兩個自訂驗證規則可能如下所示:

[MetadataType(typeof(ExpenseReportDetailsMetadata))]
[CustomValidation(typeof(ExpenseReportValidation),
  "ValidateDescription")]
public partial class ExpenseReportDetails { }

public partial class ExpenseReportDetailsMetadata {
  [Bindable(true, BindingDirection.TwoWay)]
  [CustomValidation(typeof(ExpenseReportValidation), 
    "ValidateDateIncurred")]
  [Display(Name = "Date", 
    Description = "The date of when this expense was incurred.")]
  public object DateIncurred;

在.NET RIA 服務投影 」 處理序知道在 CustomValidationAttribute,且會將它傳送至您的用戶端 Proxy。 因為自訂的驗證最有可能您要在伺服器上定義時) 的驗證型別中包含,您可以利用處理其同步處理的共用程式碼。

自訂的驗證方法簽章必須遵循特定的模式:

[Shared]
public static class ExpenseReportValidation {
  public static bool ValidateDateIncurred(object property, 
    ValidationContext context, out ValidationResult validationResult) {

    validationResult = null;
    bool result =       DateTime.Compare((DateTime)property, DateTime.Now) < 0;

    if (!result)
      validationResult = new ValidationResult(context.DisplayName + 
        " must be today or in the past.");
      return result;
  }
}

請注意,SharedAttribute ExpenseReportValidation 類別上的使用。這表示投影處理序,它不需要因為它將也會討論由共用程式碼的一部分轉譯到用戶端。

設定自動換行

在舊天內,您會藉由包裝 CRUD 周圍費用報表資料的作業開發費用報告應用程式。新的 Silverlight 3 DataGrid、 DataForm、 DataPager 和 ObjectDataSource 可讓您不必在基礎結構開發投資或犧牲使用內建的控制項的功能,快速建立 UI。此外,使用.NET RIA 服務,您可以定義完整的驗證規則和資料的存取的伺服器端商業邏輯,並讓它會是輕鬆地使用投影處理序的感謝。

我的範例費用報表仍需要報表詳細資料] 區段,以及巡覽和驗證。若要達到此目的,我要使用 Silverlight 3,以及一組.NET RIA 服務所提供的應用程式服務在某些其他控制項。日後的文章,我將示範如何運作。

Jonathan Carter 是 Microsoft 在技術。